具有相同正文的多个条件句



如何使用相同的主体在Python代码中进行多次检查以避免违反DRY?

例如,我需要在Django项目中检查这一点:

if not obj.name == instance.name:
post_response('CHANGED')
if not obj.address == instance.address:
post_response('CHANGED')
if not obj.phone_number == instance.phone_number:
post_response('CHANGED')
if not obj.postal_code == instance.postal_code:
post_response('CHANGED')

我还有多个条件运算要做。这感觉很多余,因为每个条件运算的主体都是一样的。

由于在两个对象上检查相同的属性,因此可以像这样动态比较它们:

attributes = ['name', 'address', 'phone_number', 'postal_code']
for attribute in attributes:
if not getattr(obj, attribute) == getattr(instance, attribute):
post_response('CHANGED')
break

您可以将测试与andor等逻辑运算相结合。

if not (
obj.name == instance.name and 
obj.address == instance.address and 
obj.phone_number == instance.phone_number and 
obj.postal_code == instance.postal_code):
post_response('CHANGED')

但这并不等同于您的代码,因为您使用了多个if而不是elif,因此您的构造可能会激发多次,而这只会激发一次。你可以通过计算差异的数量来做到这一点,如果这是预期的行为,那么你可以做那么多次。

changes = sum([
obj.name != instance.name,
obj.address != instance.address, 
obj.phone_number != instance.phone_number,
obj.postal_code != instance.postal_code])
for _ in range(changes):
post_response('CHANGED')

但话说回来,你可能需要考虑这是否会像这样牺牲太多的可读性,因为在这里你需要知道,你可以将布尔求和在一起,并且range(0)等于没有迭代,而你的方法可以直接理解。

好吧,Python中有一个名为getattr()的内置函数,来自Python Doc:

getattr文档

它接受两个参数,一个是用于获取属性的对象,另一个是str类型中的属性名称。

因此,对于这个问题,您可以使用要检查的属性的名称创建一个列表/元组,并在for循环中对其进行迭代:

attrNames = ('name', 'address', 'phone_numbers', 'postal_code')

for name in attrName:
if not getattr(obj, name) == getattr(instance, name):
post_response('CHANGED')

看起来您已经成功地遵守了DRY。每一行都清楚地定义了一个唯一的条件,并导致一个封装代码的函数。DRY指的是函数的内容,而不是该函数是否在多个位置被调用。你所做的似乎完全正确。

如果您在每种情况下都写了几行,并且每个块都包含相同的行,那么您可能违反了DRY。

最新更新