请考虑以下类别:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


我的同事倾向于这样定义:

class Person:
    name = None
    age = None

    def __init__(self, name, age):
        self.name = name
        self.age = age


主要这样做的原因是他们选择的编辑器显示了自动补全的属性。

我个人不喜欢后者,因为一个类将那些属性设置为None是没有道理的。

哪种方法更好?出于什么原因?

评论

永远不要让您的IDE规定您编写什么代码?

顺便说一句:使用适当的python IDE(例如PyCharm),在__init__中设置属性已经提供了自动补全等功能。此外,使用None可以防止IDE推断出更好的属性类型,因此最好使用明智的默认值(如果可能)。

如果仅用于自动完成,则可以使用类型提示,并且其他文档字符串也将是加号。

“永远不要让您的IDE决定您编写什么代码”是一个有争议的问题。从Python 3.6开始,有一个内嵌注释和一个输入模块,如果您喜欢这种话,便可以向IDE和linter提供提示...

这些在类级别的分配对其余代码没有影响。他们对自我没有影响。即使未在__init__中分配self.name或self.age,它们也不会出现在实例self中,它们只会出现在Person类中。

#1 楼

我将后一种不好的做法称为“这不会按照您的想法做”。 -global变量,这些变量从不被访问,但是它们确实占用了各个类的名称空间表(__dict__)中的空间,只是为了使我的IDE做某事。“

评论


然后有点像docstrings ;-)当然,Python有一个方便的模式可以为那些需要它的人剥离-OO。

–史蒂夫·杰索普(Steve Jessop)
2014年8月27日15:24



迄今为止,占用的空间是此约定发臭的最不重要的原因。每个名称(每个进程)一打字节。我觉得浪费时间只是在阅读与答案相关的部分,这就是节省空间成本的重要性。

–user7043
2014年8月27日在16:20



@delnan我同意条目的内存大小是没有意义的,我更认为是在逻辑/心理空间中占用了空间,进行自省式调试,因此我想这需要更多的读取和排序。我〜LL

– StarWeaver
2014年8月27日在18:46

实际上,如果您对空间如此偏执,您会注意到这可以节省空间并浪费时间。未初始化的成员会使用类值,因此没有一堆变量名映射到None(每个实例一个)。因此,该类的成本为几个字节,而每个实例节省的成本为几个字节。但是,每次失败的变量名搜索都会花费一点时间。

–琼·杰伊·奥伯马克
2014年8月27日在20:48

如果您担心8个字节,则不会使用Python。

– c z
18年4月30日在13:58

#2 楼

1.使您的代码易于理解

代码被读取的频率比书面的读取频率高。使您的代码维护人员的工作更轻松(明年也可能要自己做)。

我不知道任何硬性规则,但我更希望将任何将来的实例状态明确声明为完全无用。使用AttributeError崩溃已经很糟糕了。不清楚实例属性的生命周期会更糟。恢复可能导致调用属性分配的调用序列所需的精神上的操练很容易变得不平凡,从而导致错误。保持可变属性的数量最少。

2。不要混合类级成员和实例级成员

您在class声明中定义的任何内容都属于该类,并且由该类的所有实例共享。例如。当您在类中定义一个函数时,它将成为一个对于所有实例都相同的方法。同样适用于数据成员。这与您通常在__init__中定义的实例属性完全不同。

类级数据成员最可用作常量:

class Missile(object):
  MAX_SPEED = 100  # all missiles accelerate up to this speed
  ACCELERATION = 5  # rate of acceleration per game frame

  def move(self):
    self.speed += self.ACCELERATION
    if self.speed > self.MAX_SPEED:
      self.speed = self.MAX_SPEED
    # ...


评论


是的,但是将类级成员和实例级成员混合在一起几乎就是def所做的。它创建了我们认为是对象属性的函数,但实际上是类的成员。财产及其类似的东西也是一样。在类真正由工作介导的情况下,给人一种幻想属于工作对象的想法,这是一种久经考验的不发狂的方式。如果对于Python本身来说还可以的话,那会是多么糟糕。

–琼·杰伊·奥伯马克
2014年8月27日在18:54

好吧,Python中的方法解析顺序(也适用于数据成员)不是很简单。在实例级别找不到的内容将在类级别然后在基类之间进行搜索,等等。您确实可以通过分配同名实例级别成员来隐藏类级别成员(数据或方法)。但是实例级方法绑定到实例的self,不需要传递self,而class级方法是未绑定的,是def时间看到的普通函数,并且接受实例作为第一个参数。所以这些是不同的事情。

– 9000
2014年8月28日0:05



我认为AttributeError比有bug更好,更好。否则,您将吞噬“无”并获得毫无意义的结果。在即将在__init__中定义属性的情况下,这一点特别重要,因此缺少的属性(但在类级别存在)只能由错误继承引起。

– Davidmh
14年8月28日在0:11

@Davidmh:确实,检测到的错误总是比未检测到的错误要好!我想说的是,如果必须将属性设置为None,并且在实例构建时此值没有意义,则说明您的体系结构存在问题,必须重新考虑属性值或其初始值的生命周期。请注意,通过尽早定义属性,甚至在编写类的其余部分之前就可以检测到此类问题,更不用说运行代码了。

– 9000
2014年8月28日在2:54



好玩!导弹!无论如何,我很确定可以制作类级别的var并将其混合...只要类级别包含默认值,等等。

– Erik Aronesty
19年9月3日在18:31

#3 楼

我个人使用__ init __()方法定义成员。我从没想过在课堂上定义它们。但是我总是这样做:我初始化__ init__方法中的所有成员,甚至那些__ init__方法中不需要的成员。

示例:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._selected = None

   def setSelected(self, value):
        self._selected = value


在一个地方定义所有成员很重要。它使代码更具可读性。无论是在__init __()内部还是外部,都不那么重要。但是,对于团队来说,一定要采用几乎相同的编码风格非常重要。

评论


您应该在构造函数中设置所有值。如果该值是在类本身中设置的,则它将在实例之间共享,这对于None而言很好,但对于大多数值而言并非如此。因此,请勿对此进行任何更改。 ;)

–雷姆科·哈辛(Remco Haszing)
2014年8月27日12:34



参数的默认值以及采用任意位置和关键字参数的能力使它的痛苦比预期的要少得多。 (实际上,可以将构造委托给其他方法甚至是独立函数,因此,如果您确实需要多个调度,也可以这样做)。

– Sean Vieira
2014年8月27日14:17

@Benedict Python没有访问控制。下划线是公认的实现细节约定。参见PEP 8。

–Doval
14年8月27日在16:07

@Doval非常好的理由是在属性名称前加上_:表示它是私有的! (为什么在这个线程中有那么多人将Python与其他语言混淆或半混淆?)

–user7043
14年8月27日在16:18

啊,所以您是所有公开互动的人的属性或功能之一...对不起,我误会了。在我看来,这种风格总是显得过分,但它有一定的影响力。

–琼·杰伊·奥伯马克
2014年8月28日在14:31

#4 楼

这是一个坏习惯。您不需要这些值,它们会使代码混乱,并可能导致错误。

考虑:

>>> class WithNone:
...   x = None
...   y = None
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> class InitOnly:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> wn = WithNone(1,2)
>>> wn.x
1
>>> WithNone.x #Note that it returns none, no error
>>> io = InitOnly(1,2)
>>> InitOnly.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class InitOnly has no attribute 'x'


评论


我很难称其为“导致错误”。您在此处请求'x'是什么意思,但是您很可能想要最可能的初始值。

–琼·杰伊·奥伯马克
2014年8月27日在18:51

我应该详细说明,如果使用不正确,可能会导致错误。

–丹妮丝
2014年8月27日19:41

较高的风险仍在初始化对象。没有人真的很安全。这将导致的唯一错误是吞下真正la脚的异常。

–琼·杰伊·奥伯马克
2014年8月27日20:39

如果错误可以避免更严重的问题,则不会导致错误是一个问题。

– Erik Aronesty
19年9月3日在18:35

#5 楼

我将使用“有点像docstrings,然后”声明此无害,只要它始终是None或其他狭窄范围的值,且都是不可变的即可。

它散布着极简主义,并且对静态类型语言的过度依赖。而且它不适合作为代码。但是它在文档中仍然有一个次要目的。

它记录了预期的名称,因此,如果我与某人组合代码,而我们中的一个拥有“ username”,另一个拥有“ user_name”,提示人们,我们已经分道扬and,没有使用相同的变量。

将强制完全初始化为策略可以通过Python方式实现相同的目的,但是如果其中包含实际代码, __init__,这提供了一个更清晰的位置来记录使用中的变量。

显然,这里的大问题在于,它会诱使人们使用None以外的值进行初始化,这可能是不好的:

class X:
    v = {}
x = X()
x.v[1] = 2


保留了全局跟踪功能,并且没有为x创建实例。

但这在整个Python中比这个实践更像是一个怪癖,而且我们应该已经对此感到偏执了。