Python 3 对象构造:最符合 Python 风格的方式是什么?
我之前学过Java,那个语言比较啰嗦和严格,所以我觉得在Python中可以随意修改对象的属性,让它们有构造函数里没有的字段,这种做法真的让我觉得很“丑”。
我正在努力适应Python的思维方式,我在想我应该怎么构造我的对象。
我的直觉是应该在构造的时候传入字段,比如:
def __init__(self, foo, bar, baz=None):
self.foo = foo
self.bar = bar
self.baz = baz
不过,如果要传很多字段,这样就会变得特别啰嗦和混乱。为了解决这个问题,我觉得最好的方法是传一个字典给构造函数,从中提取字段:
def __init__(self, field_map):
self.foo = field_map["foo"]
self.bar = field_map["bar"]
self.baz = field_map["baz"] if baz in field_map else None
我想到的另一种方法是在其他地方添加字段,比如:
class Blah(object):
def __init__(self):
pass
...
blah = Blah()
blah.foo = var1
但这样对我来说感觉太随意了。
(我想我脑子里困扰我的问题是如何在Python中处理接口……)
所以,简单来说,我想问:我应该如何在Python中构造我的对象?有没有什么公认的规范?
2 个回答
我在现实中没见过你们的 field_map
,我觉得只有在代码的其他地方也用到 field_map
时,这样做才有意义。
关于你的第三个例子:虽然你不需要给它们赋值(除了 None
),但在 __init__
方法中明确声明属性是个常见的做法,这样你就能很清楚地看到你的对象有哪些属性。
所以,下面这种写法比单纯写一个空的 __init__
方法要好(这样你还会得到更高的 pylint 分数):
class Blah(object):
def __init__(self):
self.foo = None
self.bar = None
blah = Blah()
blah.foo = var1
这种方法的问题在于,初始化后你的对象可能处于一个不太明确的状态,因为你还没有定义所有的属性。这取决于你的对象逻辑(代码逻辑和含义)以及对象的工作方式。如果确实如此,我建议你不要这样做。如果你的对象依赖于 foo
和 bar
被合理地定义,你应该把它们放在 __init__
方法里。
不过,如果属性 foo
和 bar
不是必须的,你可以在之后再定义它们。
如果你觉得参数列表的可读性有问题,可以使用关键字参数。
你描述的第一种方法是非常常见的。有些人会使用更简短的方式:
class Foo:
def __init__(self, foo, bar):
self.foo, self.bar = foo, bar
你提到的第二种方法不太常见,但有一个类似的版本是:
class Thing:
def __init__(self, **kwargs):
self.something = kwargs['something']
#..
这个方法可以用来创建像这样的对象:
t = Thing(something=1)
这个方法还可以进一步修改成:
class Thing:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
这样就可以实现:
t = Thing(a=1, b=2, c=3)
print t.a, t.b, t.c # prints 1, 2, 3
正如Debilski在评论中提到的,最后一种方法有点不安全,你可以像这样添加一个被接受的参数列表:
class Thing:
keywords = 'foo', 'bar', 'snafu', 'fnord'
def __init__(self, **kwargs):
for kw in self.keywords:
setattr(self, kw, kwargs[kw])
其实有很多不同的变种,我所知道的并没有一个通用的标准。