如何使用相同的主体在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
您可以将测试与and
或or
等逻辑运算相结合。
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。