可变性比这更好,更直观Snake(False, True, 3)
:
Snake("Python", constrictor=True, poisonous=False)
Animal("Snail") # Snail has a foot but no leg. Defaults are good for it.
# Cobra eat other snakes, including poisonous, fast attacks, snake fights.
Snake("Indian cobra", moves=True, poisonous=True)
Animal("Myriapod", num_legs=750) # Changes for an idividual after every molting.
哦,关于 Python 的真正令人兴奋的问题,不仅仅是关于编程。:)
将最个性化的参数放在首位是个好主意,这些参数对于所有子类都是通用的,就像通用的“自我”本身一样。下一个非常常见的是这个例子中的名字。
如果您相信您的类永远不会被修改,并且它们将与所有实现的参数一起使用,并且您永远不会以正确的顺序出错,那么您不需要任何可变性。您可以继续使用已使用的固定位置参数。这个假设经常不成立。明天没有人会在没有看到关键字的情况下记住第一个False和第二个True应该是什么。
如果您需要使用固定位置参数调用您的类,Snake(False, True, 3)
则不能使用**kwds
这些参数中的任何一个。
A)
现在让我们期望您的示例Snake(False, True, 3)
是必需的测试用例。那么你不能将 **kwds用于任何位置参数 (poisonous, moves, num_legs)
。您只有这四种实现 __init__ 标头的可能性:(还不够好)
# the most fragile solution - easy extensible, not easy to observe the order
class Snake(Animal):
def __init__(self, *args):
self.poisonous = args.pop[0]
# or better ...pop[-1] that allows adding new parameters to the end
super(Snake,self).__init__(*args)
# now is args undefined if ancestors could eat parts from it but
# everything is in self
# the most naive solution - easy readable, not easy extensible because not DRY
class Snake(Animal):
def __init__(self, poisonous, moves, num_legs):
self.poisonous = poisonous
super(Snake,self).__init__(moves, num_legs)
# anythig between them combines disadvantages of both previous
class Snake(Animal):
def __init__(self, poisonous, *args):
self.poisonous = poisonous
super(Snake,self).__init__(*args)
class Snake(Animal):
def __init__(self, poisonous, moves, *args):
self.poisonous = poisonous
super(Snake,self).__init__(moves, *args)
.
B)
关键字参数更健壮,因为它们的一些错误可以自动报告。期望您重新定义 Animal 以增加其可变性:
class Animal(object):
def __init__(self,name, moves=True, num_legs=None):
self.name = name
self.moves = moves
self.num_legs = num_legs
# The recommended Snail !
class Snake(Animal):
def __init__(self, *args, **kwds):
"""Snake: Implements.. (Docs important, otherwise real keywords not seen in help)
kwds: (only what defined here)
poisonous: Bla bla. default=True
constrictor: Bla bla bla. default=False
"""
# A copy of kwds can be created, if manipulation with original is prohibited.
self.poisonous = kwds.pop('poisonous', True) # default: poisonous snake
self.constrictor = kwds.pop('constrictor', False)
# OK. This reports error if some keyword is misspelled and will not be consumed.
super(Snake,self).__init__(*args, **kwds)
# This Snake is more readable, but its descendants would be more complicated,
# otherwise is possible: "TypeError: got multiple values for keyword argument 'xy'".
class Snake(Animal):
def __init__(self, name, poisonous=True, constrictor=False, *args, **kwds):
self.poisonous = poisonous
self.constrictor = constrictor
super(Snake,self).__init__(name, *args, **kwds)
现在您有很大的可变性,关键字参数的顺序并不重要。