我找不到一个明确的答案。AFAIK,在Python类中不能有多个
假设我有一个名为
我只能想到一种方法来做这件事,但这似乎有点笨拙:
1 2 3 4 5 6 | class Cheese(): def __init__(self, num_holes = 0): if (num_holes == 0): # randomize number_of_holes else: number_of_holes = num_holes |
你说呢?还有别的办法吗?
实际上
1 2 3 4 | class Cheese(): def __init__(self, num_holes = None): if num_holes is None: ... |
现在,如果你想要添加更多参数的完全自由:
1 2 3 4 5 | class Cheese(): def __init__(self, *args, **kwargs): #args -- tuple of anonymous arguments #kwargs -- dictionary of named arguments self.num_holes = kwargs.get('num_holes',random_holes()) |
为了更好地解释
1 2 3 4 5 6 7 8 9 | def f(*args, **kwargs): print 'args: ', args, ' kwargs: ', kwargs >>> f('a') args: ('a',) kwargs: {} >>> f(ar='a') args: () kwargs: {'ar': 'a'} >>> f(1,2,param=3) args: (1, 2) kwargs: {'param': 3} |
http://docs.python.org/reference/expressions.html#calls
如果只使用
如果您想要多个独立的"构造函数",可以将它们作为类方法提供。这些通常称为工厂方法。在这种情况下,您可以将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Cheese(object): def __init__(self, num_holes=0): "defaults to a solid cheese" self.number_of_holes = num_holes @classmethod def random(cls): return cls(randint(0, 100)) @classmethod def slightly_holey(cls): return cls(randint(0, 33)) @classmethod def very_holey(cls): return cls(randint(66, 100)) |
现在创建这样的对象:
1 2 3 | gouda = Cheese() emmentaler = Cheese.random() leerdammer = Cheese.slightly_holey() |
如果你想使用可选参数,所有这些答案都很好,但是python的另一种可能性是使用classmethod生成工厂风格的伪构造函数:
1 2 3 4 5 6 7 8 | def __init__(self, num_holes): # do stuff with the number @classmethod def fromRandom(cls): return cls( # some-random-number ) |
对于您的实现来说,这些都是好主意,但是如果您要向用户呈现一个cheese制作界面的话。他们不关心奶酪有多少洞,也不关心制作奶酪的内部材料。代码的用户只想要"gouda"或"parmesean",对吗?
所以为什么不这样做:
1 2 3 4 5 | # cheese_user.py from cheeses import make_gouda, make_parmesean gouda = make_gouda() paremesean = make_parmesean() |
然后你可以使用上面的任何方法来实现函数:
1 2 3 4 5 6 7 8 9 10 11 12 | # cheeses.py class Cheese(object): def __init__(self, *args, **kwargs): #args -- tuple of anonymous arguments #kwargs -- dictionary of named arguments self.num_holes = kwargs.get('num_holes',random_holes()) def make_gouda(): return Cheese() def make_paremesean(): return Cheese(num_holes=15) |
这是一种很好的封装技术,我认为它更像python。对我来说,这种做事方式更符合鸭子打字的风格。您只是在请求一个gouda对象,并不真正关心它是什么类。
为什么你认为你的解决方案是"笨拙的"?我个人更喜欢一个默认值的构造函数,而不是像你的情况下的多个重载构造函数(Python不支持方法重载):
1 2 3 4 5 6 | def __init__(self, num_holes=None): if num_holes is None: # Construct a gouda else: # custom cheese # common initialization |
对于有许多不同构造函数的非常复杂的情况,使用不同的工厂函数可能会更干净:
1 2 3 4 5 6 7 8 9 | @classmethod def create_gouda(cls): c = Cheese() # ... return c @classmethod def create_cheddar(cls): # ... |
在您的cheese示例中,您可能想使用cheese的Gouda子类……
人们当然应该更喜欢已经发布的解决方案,但是因为还没有人提到这个解决方案,所以我认为为了完整性值得一提。
可以修改
如果不能根据构造函数参数的类型选择初始化类型,并且构造函数不共享代码,则可以使用这种方法。
例子:
1 2 3 4 5 6 7 8 9 10 | class MyClass(set): def __init__(self, filename): self._value = load_from_file(filename) @classmethod def from_somewhere(cls, somename): obj = cls.__new__(cls) # Does not call __init__ obj._value = load_from_somewhere(somename) return obj |
最好的答案是上面关于默认参数的那个,但是我写这篇文章很开心,而且它确实符合"多个构造函数"的要求。使用方法自负风险。
新方法怎么样?
典型的实现使用super(currentclass, cls)调用超类的new()方法来创建类的新实例。然后根据需要修改新创建的实例,然后返回它。"
因此,您可以让新方法通过附加适当的构造函数方法来修改类定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Cheese(object): def __new__(cls, *args, **kwargs): obj = super(Cheese, cls).__new__(cls) num_holes = kwargs.get('num_holes', random_holes()) if num_holes == 0: cls.__init__ = cls.foomethod else: cls.__init__ = cls.barmethod return obj def foomethod(self, *args, **kwargs): print"foomethod called as __init__ for Cheese" def barmethod(self, *args, **kwargs): print"barmethod called as __init__ for Cheese" if __name__ =="__main__": parm = Cheese(num_holes=5) |
而是使用
更根本的不同构造方法可能需要返回
我使用继承。特别是如果有比洞的数量更多的不同。特别是如果豪达需要不同的成员,那么帕尔马干酪。
1 2 3 4 5 6 7 8 | class Gouda(Cheese): def __init__(self): super(Gouda).__init__(num_holes=10) class Parmesan(Cheese): def __init__(self): super(Parmesan).__init__(num_holes=15) |
由于我最初的答案被批评为我的特殊用途构造函数没有调用(唯一的)默认构造函数,所以我在这里发布了一个修改后的版本,它满足了所有构造函数调用默认构造函数的愿望:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Cheese: def __init__(self, *args, _initialiser="_default_init", **kwargs): """A multi-initialiser. """ getattr(self, _initialiser)(*args, **kwargs) def _default_init(self, ...): """A user-friendly smart or general-purpose initialiser. """ ... def _init_parmesan(self, ...): """A special initialiser for Parmesan cheese. """ ... def _init_gauda(self, ...): """A special initialiser for Gauda cheese. """ ... @classmethod def make_parmesan(cls, *args, **kwargs): return cls(*args, **kwargs, _initialiser="_init_parmesan") @classmethod def make_gauda(cls, *args, **kwargs): return cls(*args, **kwargs, _initialiser="_init_gauda") |
我想这是一种很干净的方法,也很巧妙
1 2 3 4 5 6 7 8 9 10 | class A(object): def __init__(self,e,f,g): self.__dict__.update({k: v for k,v in locals().items() if k!='self'}) def bc(self): print(self.f) k=A(e=5,f=6,g=12) k.bc() # >>>6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Cheese: def __init__(self, *args, **kwargs): """A user-friendly initialiser for the general-purpose constructor. """ ... def _init_parmesan(self, *args, **kwargs): """A special initialiser for Parmesan cheese. """ ... def _init_gauda(self, *args, **kwargs): """A special initialiser for Gauda cheese. """ ... @classmethod def make_parmesan(cls, *args, **kwargs): new = cls.__new__(cls) new._init_parmesan(*args, **kwargs) return new @classmethod def make_gauda(cls, *args, **kwargs): new = cls.__new__(cls) new._init_gauda(*args, **kwargs) return new |
这就是我如何为我必须创建的
你可以这样用:
1 2 3 4 5 6 | >>> temp = YearQuarter(datetime.date(2017, 1, 18)) >>> print temp 2017-Q1 >>> temp = YearQuarter((2017, 1)) >>> print temp 2017-Q1 |
这就是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import datetime class YearQuarter: def __init__(self, value): if type(value) is datetime.date: self._year = value.year self._quarter = (value.month + 2) / 3 elif type(value) is tuple: self._year = int(value[0]) self._quarter = int(value[1]) def __str__(self): return '{0}-Q{1}'.format(self._year, self._quarter) |
当然,您可以使用多个错误消息展开