这个方法应该是一个类方法吗?为什么它不能访问变量?
Should this method be a classmethod and why can't it access vars?
我是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
这会引发错误:
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'
i如果我注释掉 @classmethod
,这将正常工作。
我的理解(肯定是不正确的):
当我执行 a = A()
时,然后在 __init__
中创建的所有变量(obj_var
)在传递给任何其他 [=17] 时都可以通过此 a
访问=] 相同 class.Apparently 情况并非如此。
问题
为什么在方法中提到装饰器 @classmethod
但在删除装饰器,它工作正常吗?
编译时python如何在内部处理这个特定的class?
有什么方法可以用相同的方法使用 @classmethod
和 __init__
变量吗?
我们来谈谈 Python 的方法实际上是如何工作的。
您可能已经注意到 Python 方法的声明方式与 free-standing 函数类似,但在 class 中。那是因为 Python 方法 实际上是 free-standing 恰好在 class 中的函数。 self
/cls
参数并不特殊。它只是函数的第一个参数。
在我们继续之前,我想指出您似乎没有明确继承自 object
。如果您在 Python 2.x 中工作,则图表的根部没有 object
除非您明确继承它。 这是一件坏事,您应该尽可能在新代码中直接或间接继承自object
。从 Python 3 中的 object
继承是合法且无害的,但没有必要。本讨论的其余部分假定您正在 3.x 中工作或已解决此问题。
当您使用 foo.bar
访问变量、函数、方法或任何其他类型的对象时,将调用某些称为 "descriptor protocol" 的挂钩。您无需了解其详细信息即可了解函数的工作原理。你只需要知道这个:
- 首先,如果有一个实例变量
bar
直接附加到foo
(并且foo
不是class),我们只是return它直接。(*)
- 如果
foo
是一个 class 并且 bar
是一个 @classmethod
函数(**) 在 foo
或其超类之一中声明classes,那么第一个参数在我们return之前设置为foo
。否则,它 return 不变。(***) 如果我们 return 编辑了一些东西,我们 到此为止 。
- 我们搜索
foo
的"method resolution order"。这包括 foo
的 class(称为 type(foo)
),class 的超级 class,等等,直到我们到达 object
.在多重继承的情况下,这会变得有点复杂,但同样,您不需要知道这一点。
- 从第一个 class 中取出
bar
变量(称之为 Baz
)。
- 如果
Baz.bar
是一个常规的、未修饰的函数,将其第一个参数设置为 foo
并 return 它。
- 否则,如果
Baz.bar
是一个 @classmethod
函数,将其第一个参数设置为 type(foo)
并 return 它。
- 否则,如果
Baz.bar
是一个 @staticmethod
函数,或者根本不是一个函数 (**),return 它不变。
如您所见,如果声明方法 @classmethod
,第一个参数始终是 class,而不是实例, 无论函数是如何被调用的。这意味着您无权访问 foo
的实例变量,因为您无权访问 foo
本身。 __init__()
中设置的任何变量都是实例变量,因此它们在这里不可见。
以下是我撒的所有谎言:
(*): Python 实际上先完成剩下的工作,然后再回到这一步。但这只对像 @property
这样的东西很重要,它实际上可以覆盖局部实例变量。常规方法不能。
(**):这是一个谎言。在这种情况下,Python 还对 @property
函数以及实现某些特殊方法的任何其他函数进行特殊处理。
(***):我也忽略了 Python 2.x 中的未绑定方法,因为除了某些非常奇怪的情况(当您尝试将错误类型的对象作为第一个参数),它们没有任何区别。它们不存在于 Python 3.
如果您想从 class 方法访问实例变量,您需要在存在实例变量的地方创建 class 的实例。
希望下面的代码能正常工作。
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())
我是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
这会引发错误:
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'
i如果我注释掉 @classmethod
,这将正常工作。
我的理解(肯定是不正确的):
当我执行 a = A()
时,然后在 __init__
中创建的所有变量(obj_var
)在传递给任何其他 [=17] 时都可以通过此 a
访问=] 相同 class.Apparently 情况并非如此。
问题
为什么在方法中提到装饰器
@classmethod
但在删除装饰器,它工作正常吗?编译时python如何在内部处理这个特定的class?
有什么方法可以用相同的方法使用
@classmethod
和__init__
变量吗?
我们来谈谈 Python 的方法实际上是如何工作的。
您可能已经注意到 Python 方法的声明方式与 free-standing 函数类似,但在 class 中。那是因为 Python 方法 实际上是 free-standing 恰好在 class 中的函数。 self
/cls
参数并不特殊。它只是函数的第一个参数。
在我们继续之前,我想指出您似乎没有明确继承自 object
。如果您在 Python 2.x 中工作,则图表的根部没有 object
除非您明确继承它。 这是一件坏事,您应该尽可能在新代码中直接或间接继承自object
。从 Python 3 中的 object
继承是合法且无害的,但没有必要。本讨论的其余部分假定您正在 3.x 中工作或已解决此问题。
当您使用 foo.bar
访问变量、函数、方法或任何其他类型的对象时,将调用某些称为 "descriptor protocol" 的挂钩。您无需了解其详细信息即可了解函数的工作原理。你只需要知道这个:
- 首先,如果有一个实例变量
bar
直接附加到foo
(并且foo
不是class),我们只是return它直接。(*) - 如果
foo
是一个 class 并且bar
是一个@classmethod
函数(**) 在foo
或其超类之一中声明classes,那么第一个参数在我们return之前设置为foo
。否则,它 return 不变。(***) 如果我们 return 编辑了一些东西,我们 到此为止 。 - 我们搜索
foo
的"method resolution order"。这包括foo
的 class(称为type(foo)
),class 的超级 class,等等,直到我们到达object
.在多重继承的情况下,这会变得有点复杂,但同样,您不需要知道这一点。 - 从第一个 class 中取出
bar
变量(称之为Baz
)。 - 如果
Baz.bar
是一个常规的、未修饰的函数,将其第一个参数设置为foo
并 return 它。 - 否则,如果
Baz.bar
是一个@classmethod
函数,将其第一个参数设置为type(foo)
并 return 它。 - 否则,如果
Baz.bar
是一个@staticmethod
函数,或者根本不是一个函数 (**),return 它不变。
如您所见,如果声明方法 @classmethod
,第一个参数始终是 class,而不是实例, 无论函数是如何被调用的。这意味着您无权访问 foo
的实例变量,因为您无权访问 foo
本身。 __init__()
中设置的任何变量都是实例变量,因此它们在这里不可见。
以下是我撒的所有谎言:
(*): Python 实际上先完成剩下的工作,然后再回到这一步。但这只对像 @property
这样的东西很重要,它实际上可以覆盖局部实例变量。常规方法不能。
(**):这是一个谎言。在这种情况下,Python 还对 @property
函数以及实现某些特殊方法的任何其他函数进行特殊处理。
(***):我也忽略了 Python 2.x 中的未绑定方法,因为除了某些非常奇怪的情况(当您尝试将错误类型的对象作为第一个参数),它们没有任何区别。它们不存在于 Python 3.
如果您想从 class 方法访问实例变量,您需要在存在实例变量的地方创建 class 的实例。 希望下面的代码能正常工作。
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())