类属性和实例属性有什么区别?
之间是否有任何有意义的区别:
class A(object):
foo = 5 # some default value
与
class B(object):
def __init__(self, foo=5):
self.foo = foo
如果您创建大量实例,两种样式的性能或空间要求是否有任何差异? 当你阅读代码时,你是否认为两种风格的含义有显着不同?
Is there any meaningful distinction between:
class A(object):
foo = 5 # some default value
vs.
class B(object):
def __init__(self, foo=5):
self.foo = foo
If you're creating a lot of instances, is there any difference in performance or space requirements for the two styles? When you read the code, do you consider the meaning of the two styles to be significantly different?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
存在显着的语义差异(超出性能考虑):
例如:
There is a significant semantic difference (beyond performance considerations):
For example:
不同之处在于类的属性由所有实例共享。 实例上的属性对于该实例来说是唯一的。
如果来自 C++,类的属性更像是静态成员变量。
The difference is that the attribute on the class is shared by all instances. The attribute on an instance is unique to that instance.
If coming from C++, attributes on the class are more like static member variables.
这是一篇非常好的帖子,以及摘要如下。
并以视觉形式
类属性分配
如果通过访问类来设置类属性,它将覆盖所有实例的值
<前><代码> foo = 酒吧(2)
foo.class_var
## 1
酒吧.class_var = 2
foo.class_var
## 2
如果通过访问实例来设置类变量,则它将仅覆盖所有实例的值那个实例。 这本质上覆盖了类变量,并将其转换为可用的实例变量,直观地,仅适用于该实例。
<前><代码> foo = 酒吧(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
Bar.class_var
## 1
什么时候会使用类属性?
存储常量。 由于类属性可以作为类本身的属性进行访问,因此使用它们来存储类范围内的、类特定的常量通常是不错的选择
定义默认值 。 作为一个简单的例子,我们可能会创建一个有界列表(即只能容纳一定数量或更少元素的列表)并选择默认上限为 10 个项目
Here is a very good post, and summary it as below.
And in visual form
Class attribute assignment
If a class attribute is set by accessing the class, it will override the value for all instances
If a class variable is set by accessing an instance, it will override the value only for that instance. This essentially overrides the class variable and turns it into an instance variable available, intuitively, only for that instance.
When would you use class attribute?
Storing constants. As class attributes can be accessed as attributes of the class itself, it’s often nice to use them for storing Class-wide, Class-specific constants
Defining default values. As a trivial example, we might create a bounded list (i.e., a list that can only hold a certain number of elements or fewer) and choose to have a default cap of 10 items
由于这里的评论和其他两个标记为重复的问题中的人们似乎都以同样的方式对此感到困惑,我认为值得在 亚历克斯·考文垂的。
事实上,Alex 正在分配可变类型的值(例如列表),与事物是否共享无关。 我们可以使用
id
函数或is
运算符来查看这一点:(如果您想知道为什么我使用
object()
例如,5
,这是为了避免遇到另外两个问题,出于两个不同的原因,我不想在这里讨论这些问题,完全单独创建的5
; s 最终可能是数字5
的同一个实例。但完全单独创建的object()
却不能。)那么,为什么会这样 < Alex 示例中的 code>a.foo.append(5) 会影响
b.foo
,但我示例中的a.foo = 5
不会影响? 好吧,在 Alex 的示例中尝试a.foo = 5
,并注意它不会影响那里的b.foo
。。a.foo = 5
只是将a.foo
变成5
的名称。 这不会影响b.foo
或a.foo
用来引用的旧值的任何其他名称。*我们创建的有点棘手隐藏类属性的实例属性,**但是一旦你得到了它,这里就不会发生任何复杂的事情。希望现在 Alex 使用列表的原因已经很明显了:您可以改变列表的事实意味着更容易显示两个变量命名相同的列表,也意味着在现实生活中的代码中了解是否有两个列表或同一列表的两个名称。
* 对于来自 C++ 等语言的人来说,令人困惑的是,在 Python 中,值不存储在变量中。 值本身存在于值域中,变量只是值的名称,而赋值只是为值创建一个新名称。 如果有帮助的话,请将每个 Python 变量视为
shared_ptr
而不是T
。** 有些人通过以下方式利用这一点:使用类属性作为实例属性的“默认值”,实例可以设置也可以不设置。 这在某些情况下可能很有用,但也可能会造成混乱,所以要小心。
Since people in the comments here and in two other questions marked as dups all appear to be confused about this in the same way, I think it's worth adding an additional answer on top of Alex Coventry's.
The fact that Alex is assigning a value of a mutable type, like a list, has nothing to do with whether things are shared or not. We can see this with the
id
function or theis
operator:(If you're wondering why I used
object()
instead of, say,5
, that's to avoid running into two whole other issues which I don't want to get into here; for two different reasons, entirely separately-created5
s can end up being the same instance of the number5
. But entirely separately-createdobject()
s cannot.)So, why is it that
a.foo.append(5)
in Alex's example affectsb.foo
, buta.foo = 5
in my example doesn't? Well, trya.foo = 5
in Alex's example, and notice that it doesn't affectb.foo
there either.a.foo = 5
is just makinga.foo
into a name for5
. That doesn't affectb.foo
, or any other name for the old value thata.foo
used to refer to.* It's a little tricky that we're creating an instance attribute that hides a class attribute,** but once you get that, nothing complicated is happening here.Hopefully it's now obvious why Alex used a list: the fact that you can mutate a list means it's easier to show that two variables name the same list, and also means it's more important in real-life code to know whether you have two lists or two names for the same list.
* The confusion for people coming from a language like C++ is that in Python, values aren't stored in variables. Values live off in value-land, on their own, variables are just names for values, and assignment just creates a new name for a value. If it helps, think of each Python variable as a
shared_ptr<T>
instead of aT
.** Some people take advantage of this by using a class attribute as a "default value" for an instance attribute that instances may or may not set. This can be useful in some cases, but it can also be confusing, so be careful with it.
还有一种情况。
类和实例属性是描述符。
上面将输出:
通过类或实例访问相同类型的实例返回不同的结果!
并且我在c.PyObject_GenericGetAttr 定义,以及一个很棒的 帖子。
解释
There is one more situation.
Class and instance attributes is Descriptor.
Above will output:
The same type of instance access through class or instance return different result!
And i found in c.PyObject_GenericGetAttr definition,and a great post.
Explain