Python 类变量,instance.var和instance.var之间的差异
我看到这被标记为“类变量和实例变量之间的区别是什么?”的副本,但是我不相信我在我的示例中使用了任何实例变量,我的两个类都没有Python 类变量,instance.var和instance.var之间的差异,python,python-3.x,class,Python,Python 3.x,Class,我看到这被标记为“类变量和实例变量之间的区别是什么?”的副本,但是我不相信我在我的示例中使用了任何实例变量,我的两个类都没有\uuuuu init\uuuuu我正在以两种不同的方式编辑类变量并试图理解它们之间的区别,不是类和实例变量之间的差异 我试图理解仅使用.var调用类变量与使用.class\uu.var调用类变量之间的区别。我认为这与子类化有关,所以我编写了以下代码 class Foo: foo = 0 class Bar(Foo): bar = 1 def print
\uuuuu init\uuuuu
我正在以两种不同的方式编辑类变量并试图理解它们之间的区别,不是类和实例变量之间的差异
我试图理解仅使用.var
调用类变量与使用.class\uu.var
调用类变量之间的区别。我认为这与子类化有关,所以我编写了以下代码
class Foo:
foo = 0
class Bar(Foo):
bar = 1
def print_class_vals(f, b):
""" prints both instant.var and instant.__class__.var for foo and bar"""
print("f.foo: {}, {} "
"b.foo: {}, {} "
"b.bar: {}, {} "
"".format(f.foo, f.__class__.foo,
b.foo, b.__class__.foo,
b.bar, b.__class__.bar))
f = Foo()
b = Bar()
print_class_vals(f, b)
Foo.foo += 1
print_class_vals(f, b)
Bar.foo += 1
print_class_vals(f, b)
Bar.bar += 1
print_class_vals(f, b)
这将产生以下结果:
f.foo: 0, 0, b.foo: 0, 0, b.bar: 1, 1
f.foo: 1, 1, b.foo: 1, 1, b.bar: 1, 1
f.foo: 1, 1, b.foo: 2, 2, b.bar: 1, 1
f.foo: 1, 1, b.foo: 2, 2, b.bar: 2, 2
我似乎找不到调用
inst.var
和inst.\uuu class\uuuu.var
之间的任何区别。它们有何不同?何时应该使用一个而不是另一个?Python将首先在实例名称空间/dict中查找名称(属性)。如果在那里找不到,则将在类名称空间中查找。如果仍然没有找到,那么它将遍历关于MRO(方法解析顺序)的基类
您在这里所做的是定义类属性Foo.Foo
和Bar.Bar
。
您从未修改过任何实例名称空间
试试这个:
class Foo:
foo = 1
f = Foo()
f.foo = 2
print('f.foo = {!r}'.format(f.foo))
print('f.__class__.foo = {!r}'.format(f.__class__.foo))
您将能够理解其中的区别。Python将首先在实例名称空间/dict中查找名称(属性)。如果在那里找不到,则将在类名称空间中查找。如果仍然没有找到,那么它将遍历关于MRO(方法解析顺序)的基类 您在这里所做的是定义类属性
Foo.Foo
和Bar.Bar
。
您从未修改过任何实例名称空间
试试这个:
class Foo:
foo = 1
f = Foo()
f.foo = 2
print('f.foo = {!r}'.format(f.foo))
print('f.__class__.foo = {!r}'.format(f.__class__.foo))
您将能够理解其中的差异。虽然完美地解释了这一特殊情况,但是f.foo
和f.\uu类\uuuuuuuuuuuuuuuuo
之间实际上存在差异,即使foo
没有被实例属性遮挡
比较:
>>> class Foo:
... foo = 1
... def bar(self): pass
... baz = lambda self: None
>>> f = Foo()
>>> f.foo
1
>>> f.__class__.foo
1
>>> f.bar
<bound method Foo.bar of <__main__.Foo object at 0x11948cb00>>
>>> f.__class__.bar
<function __main__.Foo.bar(self)>
>>> f.bar()
>>> f.__class__.bar()
TypeError: bar() missing 1 required positional argument: 'self'
>>类Foo:
... foo=1
... def bar(自我):通过
... baz=lambda self:无
>>>f=Foo()
>>>福福
1.
>>>f.uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
1.
>>>酒吧
>>>f.。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>f.bar()
>>>f.。uuuu类uuuuu.bar()
TypeError:bar()缺少1个必需的位置参数:“self”
对于f.baz
,情况也是如此
不同之处在于,通过直接访问f.\uuuu class\uuuuu.foo
,您正在围绕进行一次结束运行,这是使方法、@property
和类似的事情工作的原因
如果你想了解完整的细节,请阅读链接的HOWTO,但简短的版本是,它比Gabriel的回答要多一些:
Python将首先在实例名称空间/dict中查找名称(属性)。如果在那里找不到,则将在类名称空间中查找。如果仍然没有找到,那么它将遍历关于MRO(方法解析顺序)的基类 但是,如果它在类名称空间(或任何基类)中找到它,并且它找到的是一个描述符(一个带有
\uuuuu get\uuuu
方法的值),它将执行额外的步骤。细节取决于它是数据描述符还是非数据描述符(基本上,它是否也有\uuuuuu set\uuuuu
方法),但简短的版本是,它不给你值,而是对值调用\uuuu get\uuuu
,并给出该值返回的值。函数有一个\uuuuu get\uuuu
方法,该方法返回一个绑定方法;属性有一个调用属性get方法的\uuuuuuuuuuuuuuuuuuuuuuu
方法;等。虽然完美地解释了这种特殊情况,但实际上f.foo
和f.\uuuu class\uuuuuu.foo
之间存在差异,即使foo
没有被实例属性遮挡
比较:
>>> class Foo:
... foo = 1
... def bar(self): pass
... baz = lambda self: None
>>> f = Foo()
>>> f.foo
1
>>> f.__class__.foo
1
>>> f.bar
<bound method Foo.bar of <__main__.Foo object at 0x11948cb00>>
>>> f.__class__.bar
<function __main__.Foo.bar(self)>
>>> f.bar()
>>> f.__class__.bar()
TypeError: bar() missing 1 required positional argument: 'self'
>>类Foo:
... foo=1
... def bar(自我):通过
... baz=lambda self:无
>>>f=Foo()
>>>福福
1.
>>>f.uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
1.
>>>酒吧
>>>f.。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>f.bar()
>>>f.。uuuu类uuuuu.bar()
TypeError:bar()缺少1个必需的位置参数:“self”
对于f.baz
,情况也是如此
不同之处在于,通过直接访问f.\uuuu class\uuuuu.foo
,您正在围绕进行一次结束运行,这是使方法、@property
和类似的事情工作的原因
如果你想了解完整的细节,请阅读链接的HOWTO,但简短的版本是,它比Gabriel的回答要多一些:
Python将首先在实例名称空间/dict中查找名称(属性)。如果在那里找不到,则将在类名称空间中查找。如果仍然没有找到,那么它将遍历关于MRO(方法解析顺序)的基类
但是,如果它在类名称空间(或任何基类)中找到它,并且它找到的是一个描述符(一个带有
\uuuuu get\uuuu
方法的值),它将执行额外的步骤。细节取决于它是数据描述符还是非数据描述符(基本上,它是否也有\uuuuuu set\uuuuu
方法),但简短的版本是,它不给你值,而是对值调用\uuuu get\uuuu
,并给出该值返回的值。函数有一个\uuuuu get\uuuu
方法,该方法返回一个绑定方法;属性有一个调用属性get方法的\uuuuuuuuuuuuuuuuuuuuuuu
方法;等等。你不应该使用\uuu class\uu
@chepner,副本顶部的答案在最后有一个解释,讨论了为什么你会得到相同的值。如果你没有一个实例变量来隐藏类变量,那么访问类变量是绝对没有区别的。@mistermiagi实际上,这不是真的。用一个方法(或者一个函数值的类属性,这是一样的)试试看