Noo*_*tor 6 python instance-variables decorator class-method python-decorators
我来自java背景,所以我在这里有点困惑。
考虑下面的代码片段:
class A():
def __init__(self, **kwargs):
self.obj_var = "I am obj var"
@classmethod
def class_method(cls):
print cls.obj_var # this line is in question here
cls.cls_obj = "I m class object"
return cls.cls_obj
Run Code Online (Sandbox Code Playgroud)
这会引发错误:
In [30]: a = A()
In [31]: a.obj_var
Out[31]: 'I am obj var'
In [32]: a.class_method()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-32-3dcd9d512548> in <module>()
----> 1 a.class_method()
<ipython-input-29-9c0d341ad75f> in class_method(cls)
8 @classmethod
9 def class_method(cls):
---> 10 print cls.obj_var
11 cls.cls_obj = "I m class object"
12 return cls.cls_obj
AttributeError: class A has no attribute 'obj_var'
Run Code Online (Sandbox Code Playgroud)
如果我注释掉@classmethod
,这会正常工作。
我的理解(我肯定这是不正确的):
当我这样做时a = A()
,当传递给任何其他相同类时obj_var
,__init__
可以通过 this 访问创建的所有变量()。显然情况并非如此。a
classmethod
问题)
为什么当方法中提到装饰器时我无法访问__init__
var
s ,但在删除装饰器时,它工作正常?class_method
@classmethod
python在编译时如何在内部处理这个特定的类?
有什么方法可以使用@classmethod
和__init__
vars 相同的方法吗?
让我们来谈谈 Python 的方法实际上是如何工作的。
您可能已经注意到 Python 方法的声明就像独立的函数一样,但是在一个类中。那是因为 Python 方法确实是碰巧在类中的独立函数。该self
/cls
说法并不特殊。这只是函数的第一个参数。
在我们进一步讨论之前,我想指出您似乎没有明确继承自object
. 如果您在 Python 2.x 中工作,object
除非您显式继承它,否则图的根部没有。 这是一件坏事,您应该object
在新代码中尽可能直接或间接地继承。从object
Python 3 中继承是合法且无害的,但没有必要。本讨论的其余部分假设您在 3.x 中工作或已修复此问题。
当您使用 访问变量、函数、方法或任何其他类型的对象时foo.bar
,会调用某些称为“描述符协议”的挂钩。您无需了解这些细节即可了解函数的工作原理。所有你需要知道的是:
bar
直接附加的实例变量foo
(并且foo
不是一个类),我们就直接返回它。(*)foo
是一个类并且bar
是在其超类@classmethod
中foo
或其中一个超类中声明的函数(**),则foo
在我们返回它之前将第一个参数设置为。否则,它原样返回。(***) 如果我们返回了什么,我们就到此为止。foo
。这包括foo
的类(称为type(foo)
)、该类的超类,依此类推,直到我们到达object
。在多重继承的情况下,这会变得有点复杂,但同样,您不需要知道这一点。bar
从第一个类中获取变量(称为Baz
)。Baz.bar
是一个常规的、未修饰的函数,则将它的第一个参数设置为foo
并返回它。Baz.bar
是一个@classmethod
函数,将它的第一个参数设置为type(foo)
并返回它。Baz.bar
是@staticmethod
函数,或者根本不是函数(**),则原样返回。如您所见,如果方法已声明@classmethod
,则无论函数如何调用,第一个参数始终是类,而不是实例。这意味着您无权访问 的实例变量foo
,因为您无权访问其foo
自身。中设置的任何变量__init__()
都是实例变量,因此它们在此处不可见。
以下是我撒谎的所有事情:
(*):Python 实际上会先完成剩下的工作,然后再回到这一步。但这仅对诸如 之类的东西很重要@property
,它实际上可以覆盖本地实例变量。常规方法不能。
(**): 这是个谎言。@property
在这种情况下,Python 还会对函数以及其他任何实现某些特殊方法的东西进行特殊处理。
(***):我也忽略了 Python 2.x 中的未绑定方法,因为除了某些非常奇怪的情况(当您尝试手动传递错误类型的对象作为第一个参数时),它们没有任何区别. 它们在 Python 3 中不存在。
小智 5
如果要从类方法访问实例变量,则需要创建该实例变量所在的类的实例。希望下面的代码应该工作。
class A():
def __init__(self, **kwargs):
self.obj_var = "I am obj var"
@classmethod
def class_method(cls):
self = cls() # Here you are creating an instance of the class (in this case it is class A)
print(self.obj_var)
cls.cls_obj = "I m class object"
return cls.cls_obj
print(A.class_method())
Run Code Online (Sandbox Code Playgroud)