这样做有什么区别
class a:
def __init__(self):
self.val=1
Run Code Online (Sandbox Code Playgroud)
去做
class a:
val=1
def __init__(self):
pass
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 10
class a:
def __init__(self):
self.val=1
Run Code Online (Sandbox Code Playgroud)
这会创建一个类(在Py2中,一个邋,,遗留,旧式,不要那样做!类;在Py3中,令人讨厌的旧遗留类最终消失了所以这将是一个唯一的类 - - **good*kind,class a(object):
在Py2 中需要这样,每个实例都以它自己对整数对象的引用开始1
.
class a:
val=1
def __init__(self):
pass
Run Code Online (Sandbox Code Playgroud)
这会创建一个类(同类),它本身具有对整数对象的引用1
(它的实例开始时没有每个实例引用).
对于像int
值这样的不可变因素,很难看出实际的区别.例如,在任何一种情况下,如果您稍后self.val = 2
在一个实例上执行a
此操作,则会生成实例引用(在这方面,现有答案严重错误).
这种区别对于可变对象很重要,因为它们具有mutator方法,因此了解某个列表是每个实例是唯一的还是在所有实例之间共享是非常关键的.但是对于不可变对象,因为你永远不能改变对象本身但只能分配(例如self.val
,总是会产生每个实例的引用),它很小.
关于不可变量的唯一相关差异:如果您稍后分配a.val = 3
,在第一种情况下,这将影响self.val
每个实例所看到的内容(除了具有自己self.val
分配的实例或等效操作); 在第二种情况下,它不会影响self.val
任何实例所看到的内容(除了您执行过的实例del self.val
或等效操作).
其他人解释了技术差异.我将尝试解释为什么你可能想要使用类变量.
如果您只是实例化一次类,则类变量实际上是实例变量.但是,如果您要制作许多副本,或者想要在几个实例之间共享状态,那么类变量非常方便.例如:
class Foo(object):
def __init__(self):
self.bar = expensivefunction()
myobjs = [Foo() for _ in range(1000000)]
Run Code Online (Sandbox Code Playgroud)
将导致昂贵的功能()被称为百万次.如果它每次都返回相同的值,比如从数据库中获取配置参数,那么你应该考虑将它移到类定义中,这样它只被调用一次然后在所有实例中共享.
在记忆结果时我也经常使用类变量.例:
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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,baz是一种类方法; 其结果不依赖于任何实例变量.这意味着我们可以在类变量中保留结果缓存的一个副本,这样1)您不会多次存储相同的结果,以及2)每个实例都可以从其他实例缓存的结果中受益.
为了说明这一点,假设您有一百万个实例,每个实例都根据Google搜索结果进行操作.您可能更喜欢所有这些对象共享这些结果,而不是让每个对象执行搜索并等待答案.
所以我在这里不同意Lennart.在某些情况下,类变量非常方便.如果它们是适合工作的正确工具,请不要犹豫使用它们.
正如其他人所提到的,在一种情况下,它是类的属性,另一个是实例上的属性.这有关系吗?是的,在一个案例中确实如此.正如亚历克斯所说,如果价值是可变的.最好的解释是代码,所以我将添加一些代码来显示它(这就是所有这些答案的确如此):
首先是定义两个实例属性的类.
>>> class A(object):
... def __init__(self):
... self.number = 45
... self.letters = ['a', 'b', 'c']
...
Run Code Online (Sandbox Code Playgroud)
然后是一个定义两个类属性的类.
>>> class B(object):
... number = 45
... letters = ['a', 'b', 'c']
...
Run Code Online (Sandbox Code Playgroud)
现在我们使用它们:
>>> a1 = A()
>>> a2 = A()
>>> a2.number = 15
>>> a2.letters.append('z')
Run Code Online (Sandbox Code Playgroud)
一切都很好:
>>> a1.number
45
>>> a1.letters
['a', 'b', 'c']
Run Code Online (Sandbox Code Playgroud)
现在使用class属性变体:
>>> b1 = B()
>>> b2 = B()
>>> b2.number = 15
>>> b2.letters.append('z')
Run Code Online (Sandbox Code Playgroud)
一切都是......好吧......
>>> b1.number
45
>>> b1.letters
['a', 'b', 'c', 'z']
Run Code Online (Sandbox Code Playgroud)
是的,请注意,当您更改时,它为所有类更改了可变类属性.这通常不是你想要的.
如果您使用的是ZODB,则会使用许多类属性,因为它是一种使用新属性升级现有对象或在类级别上添加不会持久化的信息的便捷方法.否则你几乎可以忽略它们.