7

做和做有什么区别

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

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

3 回答 3

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

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

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

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

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

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

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

于 2009-10-11T03:15:07.690 回答
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 的观点。类变量在某些情况下非常方便。当它们是工作的正确工具时,请毫不犹豫地使用它们。

于 2009-10-11T14:52:22.780 回答
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']

现在使用类属性变体:

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

一切都是……嗯……

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

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

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

于 2009-10-11T06:47:02.753 回答