Python 3对象构造:哪个是最Pythonic /可接受的方式?

时间:2010-02-28 23:34:29

标签: python-3.x python conventions

在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中构建我的对象?是否有公认的惯例?

2 个答案:

答案 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

这种方法的问题是,在初始化之后,您的对象可能处于未明确定义的状态,因为您尚未定义所有对象的属性。这取决于对象的逻辑(代码和意义上的逻辑)以及对象的工作方式。如果是这种情况,我建议你这样做。如果您的对象依赖foobar进行有意义的定义,那么 应该将它们真正放在__init__方法中。

但是,如果属性foobar不是强制性的,您可以随后自由定义它们。

如果参数列表的可读性对您来说是个问题:使用关键字参数。