定义__init__中的成员与在python中的类体中定义成员之间的区别?

时间:2009-10-11 03:00:41

标签: python class init

之间有什么区别
class a:
   def __init__(self):
       self.val=1

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

3 个答案:

答案 0 :(得分:10)

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

这会创建一个类(在Py2中,一个粗糙,遗留,旧式,不要那样做!类;在Py3中,令人讨厌的旧遗留类最终消失了所以这会是一个唯一的类 - ** good * kind,它在Py2中需要class a(object):,这样每个实例都以它自己对整数对象1的引用开始。

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

这创建了一个类(同类),它本身具有对整数对象1的引用(它的实例开始时没有每个实例引用)。

对于像int这样的不可变值,很难看出实际的区别。例如,在任何一种情况下,如果您稍后在self.val = 2的一个实例上执行a,则会生成实例引用(现有答案在这方面严重错误)

区别对于 mutable 对象很重要,因为它们具有mutator方法,因此知道某个列表是每个实例是唯一的还是在所有实例之间共享是非常关键的。但是对于 immutable 对象,因为你永远不能更改对象本身但只能分配(例如self.val,它总是会产生每个实例的引用),它很小。

几乎是不可变的唯一相关区别:如果您稍后分配a.val = 3,在第一种情况下,这将影响每个实例所看到的self.val(除了具有自己的self.val的实例1}} 分配或等效的动作);在第二种情况下,它不会影响任何实例所看到的self.val(除了您已执行del self.val或等效操作的实例)。

答案 1 :(得分:6)

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

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

class Foo(object):
    def __init__(self):
        self.bar = expensivefunction()

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

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

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

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)每个实例都可以从其他实例缓存的结果中受益。

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

所以我在这里不同意Lennart。在某些情况下,类变量非常方便。如果它们是适合工作的正确工具,请不要犹豫使用它们。

答案 2 :(得分:5)

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

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

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

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

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

现在我们使用它们:

>>> a1 = A()
>>> a2 = A()
>>> a2.number = 15
>>> a2.letters.append('z')

一切都很好:

>>> a1.number
45
>>> a1.letters
['a', 'b', 'c']

现在使用class属性变体:

>>> b1 = B()
>>> b2 = B()
>>> b2.number = 15
>>> b2.letters.append('z')

一切都是......好吧......

>>> b1.number
45
>>> b1.letters
['a', 'b', 'c', 'z']

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

如果您使用的是ZODB,则会使用许多类属性,因为它是一种使用新属性升级现有对象或在类级别上添加不会持久化的信息的便捷方法。否则你几乎可以忽略它们。