首页 > 编程问答 >@classmethod 在 Python 的类之外做什么?

@classmethod 在 Python 的类之外做什么?

时间:2024-07-23 12:34:25浏览次数:9  
标签:python python-decorators class-method

在下面的代码中,如果存在 @classmethod 注释,则允许内部 def new() 代替目标的 __new__() -- 但该类会传递两次。如果 @classmethod 被删除,那么我们会收到类似“”的错误。 @classmethod 这里在做什么,有没有办法不用它? (我的动机是清晰的:我不理解的代码看起来像是等待发生的事故。)

"""Namedtuple annotation.

Creates a namedtuple out of a class, based on the signature of that class's
__init__ function. Defaults are respected. After namedtuple's initializer is
run, the original __init__ is run as well, allowing one to assign synthetic
parameters and internal book-keeping variables.

The class must not have varargs or keyword args.
"""     
import collections
import inspect


def namedtuple(cls):
    argspec = inspect.getargspec(cls.__init__)
    assert argspec.varargs is None
    assert argspec.keywords is None 
    non_self_args = argspec.args[1:]

    # Now we can create the new class definition, based on a namedtuple.
    bases = (collections.namedtuple(cls.__name__, non_self_args), cls)
    namespace = {'__doc__': cls.__doc__}
    newcls = type(cls.__name__, bases, namespace)

    # Here we set up the new class's __new__, which hands off to namedtuple's
    # after setting defaults.
    @classmethod
    def new(*args, **kwargs):
        kls, _kls_again = args[:2]              # The class is passed twice...?
        # Resolve default assignments with this utility from inspect.
        values = inspect.getcallargs(cls.__init__, None, *args[2:], **kwargs)
        values = [values[_] for _ in non_self_args]
        obj = super(newcls, kls).__new__(kls, *values)
        cls.__init__(obj, *values)              # Allow initialization to occur
        return obj
    # The @classmethod annotation is necessary because otherwise we get an
    # error like "unbound method new takes a class instance".

    newcls.__new__ = new

    return newcls

代码片段的目的是创建一个装饰器,它接受一个类并返回该类的“命名元组化”版本。这意味着新类表现得像一个 namedtuple ,并使用给定类的 __init__ 方法的签名作为其字段。

@classmethod 装饰器在这里是必不可少的,因为它允许 new 方法被调用为 newcls.__new__(newcls, ...) , 而不是 newcls.__new__(cls, ...) 。让我解释一下原因:

  1. __new__ 方法: 在 Python 中, __new__ 方法负责创建一个新实例并返回它。它是类的静态方法,它接收该类本身作为第一个参数(通常命名为 cls )。

  2. classmethod 装饰器: 此装饰器用于创建接受类本身作为第一个参数的方法,而不是类的实例。它是 Python 中的一种元编程方法,可以操作类本身。

  3. 在本例中: new 方法旨在替换由 namedtuple 装饰器创建的 newcls __new__ 方法。

  4. newcls 是新的“命名元组化”类。
  5. new 方法需要接收 newcls 作为第一个参数,以正确地实例化它。

如果删除 @classmethod ,会发生什么?

如果没有 @classmethod 装饰器, new 方法将成为一个普通的实例方法。这意味着它期望一个类的实例作为第一个参数( self )。当尝试使用 newcls.__new__(newcls, ...) 调用它时,Python 解释器会将 newcls 作为 self 参数传递,从而传递该类 两次 。这将导致错误“未绑定方法 new 需要一个类实例”,因为该方法期望一个实例,但接收到了一个类。

没有 @classmethod 可以吗?

从技术上讲,可以,但代码将不那么优雅,并且需要解决方法。以下是可能的解决方法:

    def new(*args, **kwargs):
        kls = args[0]  # 获取第一个参数,即类本身
        _kls_again = args[1] 
        # ...(其余代码相同)

    newcls.__new__ = classmethod(new)  # 将 new 明确绑定为类方法

在此解决方法中,我们手动将 new 绑定为类方法,使用 classmethod(new) 。这在功能上与使用 @classmethod 装饰器相同,但代码的意图可能不太清晰。

结论

@classmethod 装饰器在此代码片段中是 必不可少的 ,因为它可以确保 new 方法接收类本身作为第一个参数,从而允许它正确地替代 __new__ 方法。删除它需要解决方法,这可能会降低代码的可读性和可维护性。

标签:python,python-decorators,class-method
From: 32170934

相关文章

  • 三种语言实现快速选择(C++/Python/Java)
    题目给定一个长度为......
  • 如何让SublimeText支持Python 3的注释?
    我测试了SublimeText2和3,两者都有错误:如果您测试此代码,您会注意到:之后的所有代码都不会正确突出显示语法。deffoo(a,b)->str:#Nothinggetsproperlycoloredfromhere#Abunchofcode…return"bar"我发现了一些链接,解释了如何......
  • 如何用可变长度注释Python列表
    如何为可变长度或None的Python列表编写注释?当我这样写时,它会返回一个错误。defsome_function(params:list[str,...])#thisgiveserror:`TypeError:'type'objectisnotsubscriptable`defsome_function(params:List[str,...])#thisalsogiveserro......
  • Python 协议和 Django 模型
    假设我有一个简单的协议A和一个未能实现该协议的类B:fromtypingimportProtocolclassA(Protocol):deffoo(self)->str:...classB:pass当下面的代码进行类型检查时,Mypy将正确地抱怨x:A=B()mypy.error:Incompatibletypes......
  • Python字段的字符串注释
    Python是否支持类字段的任何类型的字符串注释?例如,在Golang中,我可以定义这样的结构,带有可选的字符串标签:typeUserstruct{Namestring`example:"name"`}我需要在Python中定义一个新类,其中包含包含点.的字段名称。我希望可能有某种方法来注释字段,或者......
  • 具有未定义变量和注释的有效 Python 行
    我来了一篇文章,其中包含未定义的变量名称和某些类型注释。该行有效。它有什么作用以及可能的用途是什么?withundefinedvariablenamewithsometypeannotation.Thelineisvalid.Whatitdoesandwhatarepossibleusages?>>>x:int>>>xTraceback(mostr......
  • 使用 Python 通过逻辑应用运行长时间运行的 Azure Functions
    我已经尝试解决这个问题有一段时间了,但我似乎找不到解决方案。因此,正如标题所示,我试图通过函数在逻辑应用程序中运行长时间运行的操作。我有一个python代码,可以比较2个excel文件并进行一些转换。它工作正常,但是,Excel文件包含近20k行(它是动态的,将来会添加更多行),因此......
  • 使用递归函数计算阶乘时,我在 python 中遇到类型错误
    defcalc_fact(n):如果(n==1或n==0):返回1别的:n*calc_fact(n-1)print(calc_fact(5))试图创建函数来计算阶乘,不支持类型错误操作数*:对于int或Nonetype我不知道为什么谢谢Python代码中出现“类型错误:不支持的操作数类型为*:'int'和'NoneType'”表明你......
  • 如何调试 python Flask [84] [CRITICAL] WORKER TIMEOUT?
    调试:gtts.tts:保存到temp.mp37月22日09:10:56PM[2024-07-2215:40:56+0000][84][严重]工作超时(pid:87)|||7月22日09:10:56PM[2024-07-2215:40:56+0000][87][INFO]工人退出(pid:87)7月22日09:10:57PM[2024-07-2215:40:57+0000][95][INF......
  • 类型错误:无法将函数返回值转换为 Python 类型!签名是 () -> 处理 anaconda spider
    这是代码:importosimportrandomimportnumpyasnpimportpandasaspdimporttensorflowastffromtensorflow.kerasimportbackendasKfromtensorflow.keras.layersimportDense,Dropout,Flatten,Conv2D,MaxPool2D,Input......