我经常发现自己覆盖了父类的方法,并且永远无法决定是否应该显式列出给定的参数或仅使用毯子*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
显式变体的感知好处
- 更明确(Python 之禅)
- 更容易掌握
- 功能参数很容易访问
毯子变体的感知好处
- more DRY
- 父类很容易互换
- 父方法中默认值的更改会在不触及其他代码的情况下传播
里氏替换原则
通常,您不希望方法签名在派生类型中发生变化。如果您想交换派生类型的使用,这可能会导致问题。这通常被称为里氏替换原则 http://en.wikipedia.org/wiki/Liskov_substitution_principle.
显式签名的好处
同时,我认为您的所有方法都有以下签名是不正确的*args
, **kwargs
。显式签名:
- 通过良好的参数名称帮助记录方法
- 通过指定需要哪些参数以及哪些参数具有默认值来帮助记录该方法
- 提供隐式验证(缺少必需的参数会引发明显的异常)
可变长度参数和耦合
不要将可变长度参数误认为是良好的耦合实践。父类和派生类之间应该有一定程度的内聚力,否则它们不会相互关联。相关代码产生反映内聚程度的耦合是正常的。
使用可变长度参数的地方
使用可变长度参数不应该是您的首选。当您有充分的理由时应该使用它,例如:
- 定义函数包装器(即装饰器)。
- 定义参数多态函数。
- 当您可以采用的参数确实是完全可变的时(例如广义的数据库连接函数)。 DB连接函数通常需要一个连接字符串 http://en.wikipedia.org/wiki/Connection_string有许多不同的形式,包括单参数形式和多参数形式。对于不同的数据库也有不同的选项集。
- ...
你做错了什么吗?
如果您发现经常创建采用许多参数的方法或具有不同签名的派生方法,那么您在如何组织代码方面可能会遇到更大的问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)