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

发布于 2024-08-23 10:50:50 字数 870 浏览 6 评论 0原文

我有 Java 背景,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

我能想到的另一种机制是将字段添加到其他地方 em>,例如:

class Blah(object):

    def __init__(self):
        pass

...

blah = Blah()
blah.foo = var1

但这对我来说感觉方式太松了。

(我想我脑子里的问题是如何在 Python 中处理接口...)

所以,重申一下这个问题:我应该如何在 Python 中构造我的对象?有公认的约定吗?

Having a background in Java, which is very verbose and strict, I find the ability to mutate Python objects as to give them with fields other than those presented to the constructor really "ugly".

Trying to accustom myself to a Pythonic way of thinking, I'm wondering how I should allow my objects to be constructed.

My instinct is to have to pass the fields at construction time, such as:

def __init__(self, foo, bar, baz=None):
    self.foo = foo
    self.bar = bar
    self.baz = baz

But that can become overly verbose and confusing with many fields to pass. To overcome this I assume the best method is to pass one dictionary to the constructor, from which the fields are extracted:

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

The other mechanism I can think of is to have the fields added elsewhere, such as:

class Blah(object):

    def __init__(self):
        pass

...

blah = Blah()
blah.foo = var1

But as that feels way too loose for me.

(I suppose the issue in my head is how I deal with interfaces in Python...)

So, to reiterate the question: How I should construct my objects in Python? Is there an accepted convention?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

未蓝澄海的烟 2024-08-30 10:50:50

你描述的第一个很常见。有些人使用较短的

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])

有很多变体,据我所知没有通用标准。

The first you describe is very common. Some use the shorter

class Foo:
   def __init__(self, foo, bar):
       self.foo, self.bar = foo, bar

Your second approach isn't common, but a similar version is this:

class Thing:
   def __init__(self, **kwargs):
       self.something = kwargs['something']
       #..

which allows to create objects like

t = Thing(something=1)

This can be further modified to

class Thing:
   def __init__(self, **kwargs):
       self.__dict__.update(kwargs)

allowing

t = Thing(a=1, b=2, c=3)
print t.a, t.b, t.c # prints 1, 2, 3

As Debilski points out in the comments, the last method is a bit unsafe, you can add a list of accepted parameters like this:

class Thing:
    keywords = 'foo', 'bar', 'snafu', 'fnord'
    def __init__(self, **kwargs):
        for kw in self.keywords:
            setattr(self, kw, kwargs[kw])

There are many variations, there is no common standard that I am aware of.

纵山崖 2024-08-30 10:50:50

我在现实生活中没见过很多 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 不是必需的,那么您可以在以后自由定义它们。

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

I’ve not seen many of your field_maps in real life. I think that would only make sense if you were to use the field_map at some other place in your code as well.

Concerning your third example: Even though you don’t need to assign to them (other than None), it is common practice to explicitly declare attributes in the __init__ method, so you’ll easily see what properties your object has.

So the following is better than simply having an empty __init__ method (you’ll also get a higher pylint score for that):

class Blah(object):
    def __init__(self):
        self.foo = None
        self.bar = None

blah = Blah()
blah.foo = var1

The problem with this approach is, that your object might be in a not well-defined state after initialisation, because you have not yet defined all of your object’s properties. This depends on your object’s logic (logic in code and in meaning) and how your object works. If it is the case however, I’d advise you not to do it this way. If your object relies on foo and bar to be meaningfully defined, you should really put them inside of your __init__ method.

If, however, the properties foo and bar are not mandatory, you’re free to define them afterwards.

If readability of the argument lists is an issue for you: Use keyword arguments.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文