我经常发现自己在重写父类的方法,并且永远无法决定是应该显式地列出给定的参数,还是仅仅使用一个blanket*args, **kwargs
构造。一个版本比另一个好吗?有最佳实践吗?我缺少什么好处?
class Parent(object):
def save(self, commit=True):
# ...
class Explicit(Parent):
def save(self, commit=True):
super(Explicit, self).save(commit=commit)
# more logic
class Blanket(Parent):
def save(self, *args, **kwargs):
super(Blanket, self).save(*args, **kwargs)
# more logic
外显变量的感知益处
总括变量的感知益处
Liskov替代原理
通常,您不希望方法签名在派生类型中有所不同。如果要交换派生类型的使用,这可能会导致问题。这通常被称为Liskov Substitution Principle。
显式签名的好处
同时,我不认为所有方法的签名都是
*args
,**kwargs
是正确的。显式签名:可变长度参数和耦合
不要将可变长度参数误认为是良好的耦合实践。父类和派生类之间应该有一定的内聚性,否则它们不会相互关联。相关代码导致反映内聚级别的耦合是正常的。
使用可变长度参数的位置
使用可变长度参数不应该是第一个选择。当你有一个很好的理由,比如:
你做错什么了吗?
如果您发现您经常创建带有许多参数的方法或具有不同签名的派生方法,那么您在如何组织代码方面可能会遇到更大的问题。
如果您确定Child将保留签名,那么显式方法当然更可取,但是当Child将更改签名时,我个人更喜欢使用这两种方法:
这样,签名中的更改在子签名中是可读的,而原始签名在父签名中是可读的。
在我看来,当您有多重继承时,这也是更好的方法,因为当您没有args和kwargs时,多次调用
super
是非常令人厌恶的。值得一提的是,这也是很多Python lib和框架(Django、Tornado、Requests、Markdown等等)中的首选方法。虽然人们不应该把自己的选择建立在这样的基础上,但我只是暗示,这种方法相当普遍。
我的选择是:
它避免从
*args
和**kwargs
访问commit参数,并且如果Parent:save
的签名更改(例如添加一个新的默认参数),它可以保证安全。更新:在这种情况下,如果向父级添加了新的位置参数,则使用*参数可能会导致问题。我只保留
**kwargs
,只管理具有默认值的新参数。这样可以避免传播错误。相关问题 更多 >
编程相关推荐