在Java中有一个非常冗长和严格的背景,我发现能够改变Python对象,以便为它们提供除了提交给构造函数之外的字段真的“丑陋”。
试着让自己习惯于Pythonic的思维方式,我想知道如何构建我的对象。
我的直觉是必须在施工时传递字段,例如:
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中的 interfaces ...)
所以,重申一个问题:我应该如何在Python中构建我的对象?是否有公认的惯例?
答案 0 :(得分:9)
你描述的第一个很常见。有些使用较短的
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])
有很多变化,我没有共同的标准。
答案 1 :(得分:3)
我在现实生活中没见过很多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
不是强制性的,您可以随后自由定义它们。
如果参数列表的可读性对您来说是个问题:使用关键字参数。