@classmethod的位置
我想知道在Python的源代码中,装饰器类方法(decorator classmethod)的源代码在哪里。具体来说,我在找2.7.2版本中它被定义的确切文件,但有点困难。
3 个回答
我在 ms-python.vscode-pylance-2022.1.3...\stdlib\builtins.pyi 这个文件里发现了这个内容:
class staticmethod(Generic[_R]):
__func__: Callable[..., _R]
__isabstractmethod__: bool
def __init__(self: staticmethod[_R], __f: Callable[..., _R]) -> None: ...
def __get__(self, __obj: _T, __type: type[_T] | None = ...) -> Callable[..., _R]: ...
if sys.version_info >= (3, 10):
__name__: str
__qualname__: str
__wrapped__: Callable[..., _R]
def __call__(self, *args: Any, **kwargs: Any) -> _R: ...
class classmethod(Generic[_R]):
__func__: Callable[..., _R]
__isabstractmethod__: bool
def __init__(self: classmethod[_R], __f: Callable[..., _R]) -> None: ...
def __get__(self, __obj: _T, __type: type[_T] | None = ...) -> Callable[..., _R]: ...
if sys.version_info >= (3, 10):
__name__: str
__qualname__: str
__wrapped__: Callable[..., _R]
在编程中,有时候我们会遇到一些问题,像是代码运行不正常或者出现错误。这些问题可能是因为我们没有正确理解某些概念或者使用了不合适的代码。
比如说,如果你在写代码的时候,发现某个变量的值不是你预期的那样,这可能是因为你在赋值的时候出错了。或者你可能在使用某个函数时,没有传入正确的参数,这样函数就无法正常工作。
解决这些问题的一个好方法就是仔细检查你的代码,看看每一步是不是都按照你想的那样进行。你也可以在网上查找相关的资料,看看其他人是怎么解决类似的问题的。
总之,编程就像拼图,有时候需要耐心和细心,才能把所有的部分都拼在一起,形成一个完整的图案。
tar -zxf Python-2.7.2.tgz
vim Python-2.7.2/Objects/funcobject.c
...
589 /* Class method object */
590
591 /* A class method receives the class as implicit first argument,
592 just like an instance method receives the instance.
593 To declare a class method, use this idiom:
594
595 class C:
596 def f(cls, arg1, arg2, ...): ...
597 f = classmethod(f)
598
599 It can be called either on the class (e.g. C.f()) or on an instance
600 (e.g. C().f()); the instance is ignored except for its class.
601 If a class method is called for a derived class, the derived class
602 object is passed as the implied first argument.
603
604 Class methods are different than C++ or Java static methods.
605 If you want those, see static methods below.
606 */
...
我不打算直接回答你问的问题,但下面的代码展示了一个用纯Python写的类似于classmethod
的装饰器,因为源代码中的那个是用C语言写的,具体在Python的源代码里,正如Mishna在他的回答中提到的(链接已更新为GitHub上的cPython开发分支)。
类方法的核心思想是使用“描述符”机制,具体可以参考Python的数据模型。这样,__get__
方法会返回一个函数对象,当这个函数被调用时,会用预先填好的第一个参数去调用原来的方法:
class myclassmethod(object):
def __init__(self, method):
self.method = method
def __get__(self, instance, cls):
return lambda *args, **kw: self.method(cls, *args, **kw)
在Python控制台上:
>>> class MyClass(object):
... @myclassmethod
... def method(cls):
... print cls
...
>>>
>>> m = MyClass()
>>> m.method()
<class '__main__.MyClass'>
>>>
*** 编辑 - 更新 ***
提问者进一步问道:“如果我想让装饰器也接受一个参数,初始化的正确格式应该是什么?” -
在这种情况下,不仅仅是__init__
需要改变。一个接受配置参数的装饰器实际上是分“两个阶段”来调用的——第一阶段是注解参数,并返回一个可调用的对象;第二阶段只接受将要被装饰的函数。
有几种方法可以做到这一点,但我认为最简单直接的方法是创建一个返回上面类的函数,比如:
def myclasmethod(par1, par2, ...):
class _myclassmethod(object):
def __init__(self, method):
self.method = method
def __get__(self, instance, cls):
# make use of par1, par2,... variables here at will
return lambda *args, **kw: self.method(cls, *args, **kw)
return _myclassmethod