在__init__ 中定义一个成员和在python的类体中定义它之间的区别?

Difference between defining a member in __init__ to defining it in the class body in python?

做和做有什么区别

1
2
3
class a:
   def __init__(self):
       self.val=1

1
2
3
4
class a:
   val=1
   def __init__(self):
       pass


1
2
3
class a:
   def __init__(self):
       self.val=1

这就创建了一个类(在PY2中,一个粗糙的、遗留的、旧样式的类,不要这样做!类;在Py3中,讨厌的旧遗留类最终消失了,因此这将是唯一的类,**好的类,它要求Py2中的class a(object):,这样每个实例都以自己对整数对象1的引用开始。

1
2
3
4
class a:
   val=1
   def __init__(self):
       pass

这将创建一个类(同一类),该类本身引用了整数对象1(其实例从没有每个实例引用开始)。

对于像int值这样的不变值,很难看到实际的差异。例如,在这两种情况下,如果您稍后在一个a实例上执行self.val = 2,这将提供一个实例引用(在这方面,现有的答案是严重错误的)。

区别对于可变对象很重要,因为它们有可变方法,所以知道某个列表对于每个实例是唯一的还是在所有实例之间共享是非常重要的。但是对于不可变的对象,因为您永远不能更改对象本身,而只能分配(例如,分配给self.val,它总是对每个实例进行引用),所以它非常小。

关于不可变项的唯一相关区别:如果您以后分配a.val = 3,在第一种情况下,这将影响每个实例所看到的self.val(除了分配给自己的self.val或同等操作的实例);在第二种情况下,它不会影响任何实例所看到的self.val。(除了您执行过del self.val或同等行动的情况)。


其他人解释了技术差异。我将尝试解释为什么您可能想要使用类变量。

如果只实例化一次类,那么类变量实际上就是实例变量。但是,如果您要复制许多副本,或者希望在几个实例之间共享状态,那么类变量非常方便。例如:

1
2
3
4
5
class Foo(object):
    def __init__(self):
        self.bar = expensivefunction()

myobjs = [Foo() for _ in range(1000000)]

将导致调用昂贵的函数()一百万次。如果每次返回相同的值,比如从数据库中获取一个配置参数,那么您应该考虑将它移到类定义中,这样它只被调用一次,然后在所有实例中共享。

我在记忆结果时也经常使用类变量。例子:

1
2
3
4
5
6
7
8
9
10
11
class Foo(object):
    bazcache = {}

    @classmethod
    def baz(cls, key):
        try:
            result = cls.bazcache[key]
        except KeyError:
            result = expensivefunction(key)
            cls.bazcache[key] = result
        return result

在本例中,baz是一个类方法;其结果不依赖于任何实例变量。这意味着我们可以在类变量中保留结果缓存的一个副本,这样1)您就不会多次存储相同的结果,2)每个实例都可以从其他实例缓存的结果中获益。

为了举例说明,假设您有一百万个实例,每个实例都操作一个谷歌搜索的结果。您可能更喜欢所有这些对象共享这些结果,而不是让每个对象执行搜索并等待答案。

所以我不同意伦纳德的观点。在某些情况下,类变量非常方便。当他们是合适的工作工具时,不要犹豫使用他们。


正如其他人提到的,在一种情况下,它是类上的一个属性,而在另一种情况下是实例上的一个属性。这有关系吗?是的,有一种情况是这样的。如亚历克斯所说,如果值是可变的。最好的解释是代码,所以我会添加一些代码来显示它(这就是所有的答案,真的):

首先是定义两个实例属性的类。

1
2
3
4
5
>>> class A(object):
...     def __init__(self):
...         self.number = 45
...         self.letters = ['a', 'b', 'c']
...

然后是定义两个类属性的类。

1
2
3
4
>>> class B(object):
...     number = 45
...     letters = ['a', 'b', 'c']
...

现在我们使用它们:

1
2
3
4
>>> a1 = A()
>>> a2 = A()
>>> a2.number = 15
>>> a2.letters.append('z')

一切都很好:

1
2
3
4
>>> a1.number
45
>>> a1.letters
['a', 'b', 'c']

现在使用类属性变体:

1
2
3
4
>>> b1 = B()
>>> b2 = B()
>>> b2.number = 15
>>> b2.letters.append('z')

一切都是……嗯……

1
2
3
4
>>> b1.number
45
>>> b1.letters
['a', 'b', 'c', 'z']

是的,请注意,当您更改时,所有类的可变类属性都发生了更改。这通常不是你想要的。

如果您使用的是ZODB,那么就需要使用大量的类属性,因为它是一种方便的方法,可以使用新属性升级现有对象,或者在不持久化的类级别上添加信息。否则你可以忽略它们。