关于Python继承classmethod的一些问题
Some problems about Python inherited classmethod
我有这个代码:
from typing import Callable, Any
class Test(classmethod):
def __init__(self, f: Callable[..., Any]):
super().__init__(f)
def __get__(self,*args,**kwargs):
print(args) # why out put is (None, <class '__main__.A'>) where form none why no parameter 123
# where was it called
return super().__get__(*args,**kwargs)
class A:
@Test
def b(cls,v_b):
print(cls,v_b)
A.b(123)
为什么输出是(None, <class '__main__.A'>)
? None
是从哪里来的,为什么不是 参数 123,这是我调用它的值?
当 方法 b
从 A
class 中检索时调用 __get__
方法。它与 b
.
的实际 调用 无关
为了说明这一点,将对 b
的访问与对 b
的实际调用分开:
print("Getting a reference to method A.b")
method = A.b
print("I have a reference to the method now. Let's call it.")
method()
这会产生以下输出:
Getting a reference to method A.b
(None, <class '__main__.A'>)
I have a reference to the method now. Let's call it.
<class '__main__.A'> 123
所以你看,__get__
中的输出没有显示任何有关你调用 b
的参数的信息是正常的,因为你还没有进行调用。
输出None, <class '__main__.A'>
符合Python documentation on __get__
:
object.__get__(self, instance, owner=None)
Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). The optional owner argument is the owner class, while instance is the instance that the attribute was accessed through, or None
when the attribute is accessed through the owner.
在您的情况下,您使用它来访问 class (A
) 的属性 (b
) -- 不是A
的一个实例——这样就解释了 instance
参数是 None
而 owner
参数是你的 class A
.
使用 print(cls,v_b)
生成的第二个输出将为 cls
打印 <class '__main__.A'>
,因为当您调用 class[ 时会发生这种情况=67=] 方法(相对于 实例 方法)。同样,来自 documentation:
When a class attribute reference (for class C
, say) would yield a class method object, it is transformed into an instance method object whose __self__
attribute is C
.
此处描述了您的情况,其中 A
是 class,因此第一个参数(您称为 cls
)将获得值 A
。
您可以在同一个函数上应用多个装饰器,例如,
- 第一个(和外部)装饰器可以是类方法
- 第二个(做你的事情)可以定义一个包装器,你可以像往常一样接受你的参数
In [4]: def test_deco(func):
...: def wrapper(cls, *args, **kwds):
...: print("cls is", cls)
...: print("That's where 123 should appear>>>", args, kwds)
...: return func(cls, *args, **kwds)
...:
...: return wrapper
...:
...:
...: class A:
...: @classmethod
...: @test_deco
...: def b(cls, v_b):
...: print("That's where 123 will appear as well>>>", v_b)
...:
...:
...: A.b(123)
cls is <class '__main__.A'>
That's where 123 should appear>>> (123,) {}
That's where 123 will appear as well>>> 123
In [5]:
It's too much trouble to use two at a time i want only use one like it
可以定义一个应用几个其他装饰器的装饰器:
def my_super_decorator_doing_everything_at_once(func):
return classmethod(my_small_decorator_doing_almost_everything(func))
之所以可行,是因为装饰器表示法
@g
@f
def x(): ...
是一种可读的表达方式
def x(): ...
x = g(f(x))
我有这个代码:
from typing import Callable, Any
class Test(classmethod):
def __init__(self, f: Callable[..., Any]):
super().__init__(f)
def __get__(self,*args,**kwargs):
print(args) # why out put is (None, <class '__main__.A'>) where form none why no parameter 123
# where was it called
return super().__get__(*args,**kwargs)
class A:
@Test
def b(cls,v_b):
print(cls,v_b)
A.b(123)
为什么输出是(None, <class '__main__.A'>)
? None
是从哪里来的,为什么不是 参数 123,这是我调用它的值?
当 方法 b
从 A
class 中检索时调用 __get__
方法。它与 b
.
为了说明这一点,将对 b
的访问与对 b
的实际调用分开:
print("Getting a reference to method A.b")
method = A.b
print("I have a reference to the method now. Let's call it.")
method()
这会产生以下输出:
Getting a reference to method A.b
(None, <class '__main__.A'>)
I have a reference to the method now. Let's call it.
<class '__main__.A'> 123
所以你看,__get__
中的输出没有显示任何有关你调用 b
的参数的信息是正常的,因为你还没有进行调用。
输出None, <class '__main__.A'>
符合Python documentation on __get__
:
object.__get__(self, instance, owner=None)
Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). The optional owner argument is the owner class, while instance is the instance that the attribute was accessed through, or
None
when the attribute is accessed through the owner.
在您的情况下,您使用它来访问 class (A
) 的属性 (b
) -- 不是A
的一个实例——这样就解释了 instance
参数是 None
而 owner
参数是你的 class A
.
使用 print(cls,v_b)
生成的第二个输出将为 cls
打印 <class '__main__.A'>
,因为当您调用 class[ 时会发生这种情况=67=] 方法(相对于 实例 方法)。同样,来自 documentation:
When a class attribute reference (for class
C
, say) would yield a class method object, it is transformed into an instance method object whose__self__
attribute isC
.
此处描述了您的情况,其中 A
是 class,因此第一个参数(您称为 cls
)将获得值 A
。
您可以在同一个函数上应用多个装饰器,例如,
- 第一个(和外部)装饰器可以是类方法
- 第二个(做你的事情)可以定义一个包装器,你可以像往常一样接受你的参数
In [4]: def test_deco(func):
...: def wrapper(cls, *args, **kwds):
...: print("cls is", cls)
...: print("That's where 123 should appear>>>", args, kwds)
...: return func(cls, *args, **kwds)
...:
...: return wrapper
...:
...:
...: class A:
...: @classmethod
...: @test_deco
...: def b(cls, v_b):
...: print("That's where 123 will appear as well>>>", v_b)
...:
...:
...: A.b(123)
cls is <class '__main__.A'>
That's where 123 should appear>>> (123,) {}
That's where 123 will appear as well>>> 123
In [5]:
It's too much trouble to use two at a time i want only use one like it
可以定义一个应用几个其他装饰器的装饰器:
def my_super_decorator_doing_everything_at_once(func):
return classmethod(my_small_decorator_doing_almost_everything(func))
之所以可行,是因为装饰器表示法
@g
@f
def x(): ...
是一种可读的表达方式
def x(): ...
x = g(f(x))