@staticmethod返回值

2024-05-08 19:49:42 发布

您现在位置:Python中文网/ 问答频道 /正文

在python3.6中,我试图在AbstractBaseClass中定义一个属性;我的第一次尝试是这样的(后来我发现我可以省略@staticmethod):

class AnAbstractClass(ABC):
    @property
    @staticmethod
    @abstractmethod
    def my_property():
        pass

不过,PyCharm向我展示了一个关于房产装饰商的警告: PyCharm warning

据我所知,@staticmethod修饰符不返回可调用的,而是返回不同的值。 (我怀疑这也会导致mypy在代码中的返回值类型上引发错误,但是我无法在较小的代码示例中重现该问题)。在

这是怎么回事?在


Tags: 代码属性定义mydefpropertypassclass
1条回答
网友
1楼 · 发布于 2024-05-08 19:49:42

要理解为什么收到警告,您需要对decorators和{a2}都有一点了解。在

装饰师

decorator是一个可调用的函数,它替换它正在装饰的东西,并将其分配给命名空间中的相同名称。通常,decorator用于函数和类来添加一些功能,比如类型检查或线程之类的,但实际上它们可以返回任何内容。在

由于decorator的输出不必与输入具有相同的类型,也不必执行任何相同的处理,所以decorator的顺序非常重要。decorator的应用顺序是从最接近函数的到列表顶部的。在您的例子中,abstractmethod,然后staticmethod,然后property。在

描述符

描述符定义了一个相当复杂的协议,允许使用它们提供的绑定行为对对象进行定制。出于您的目的,您需要知道函数是描述符,并且将它们放入类对象中会用到这一点。当您调用在类实例上的类中定义的任何描述符时,描述符协议使用描述符的__get__方法将该描述符绑定到该实例。描述符本身甚至不必是可调用的,而且__get__的返回值也不必是可调用的,尽管在大多数情况下,它是预期的。对于函数,__get__返回一个闭包,该闭包自动将self作为第一个位置参数传递。在

例如,给定一个方法为def b(self, arg):的类A,以及该类的一个名为a的实例,a.b(arg)将变成{}。因此,虽然b被定义为有两个位置参数,但在对实例调用时只需要显式地传入一个。但是,当您通过类调用b,例如A.b(a, arg),它只是一个普通函数,您需要手动传递所有参数,包括self。在

把它们放在一起

^{}^{}^{}都是返回可调用描述符对象的修饰符。但是,它们的描述符的__get__方法的工作方式与普通函数对象的__get__略有不同。在

abstractmethod创建了一个相当普通的类方法,但它与元类^{}交互,因此当您试图用抽象方法实例化一个类时,会出现各种有用的错误。它不会以任何方式修改结果所期望的输入参数。事实上,文档暗示了这样一个事实,即所有的副作用都可能与元类有关,并且原始输入只是传递。这里唯一要记住的是

When abstractmethod() is applied in combination with other method descriptors, it should be applied as the innermost decorator, as shown in the following usage examples: ...

你的代码似乎遵循了这条禁令。事实上,abstractmethod与你的警告没有任何关系,但无论如何在这里提到它似乎是个好主意。在

staticmethod返回一个可调用的方法,该方法绕过常规绑定行为来创建一个不关心从哪个类或实例调用它的方法。特别是,使用staticmethod.__get__绑定的方法将把它的参数传递给函数,而不是先在self前面加上__get__基本上只返回原始函数)。您可以想象,对于希望接收self参数的对象来说,这将是一个问题,比如属性的setter。在

abstractmethodstaticmethod不同,property创建了一个数据描述符。这意味着它返回一个同时具有__get__绑定和__set__绑定(以及__del__绑定)的对象。属性的__get__方法的工作原理与普通函数的__get__方法非常相似,但具体应用于getter函数。property非常关心从哪个实例调用它,因为您当然希望不同的实例具有属性包装的不同值。在

所以你的代码是staticmethod后跟property。第一个修饰符返回一个函数,该函数在绑定时不在其参数列表前加self,而第二个修饰符则需要这样做。没有什么可以阻止您调用decorator,但是IDE警告告诉您,您将无法成功调用结果对象。如果您试图在AnyAbstractClass的具体实现上访问{},您可能会得到一个TypeError,告诉您{}不接受任何位置参数,但是已经给出了一个,因为property.__get__将在静态方法的参数列表前面加上{},该方法不接受任何参数。在

请记住,将staticmethod应用于property的结果也不会有太大帮助。property实例根本不可调用。它完全通过它的__get____set____del__方法进行操作,而staticmethod假设您传入了一个可调用的。在

解决方案

正如您正确发现的那样,staticmethod和{}不能很好地混合。属性,就其本身的性质而言,应该始终知道它所操作的实例。正确的方法是添加一个self参数并允许正常方法绑定发生。在

propertystaticmethod都能很好地使用abstractmethod(只要先应用abstractmethod),因为它不会对原始函数进行任何更改。实际上,abstractmethod的文档特别提到,property抽象的getter、setter或deleter使整个属性抽象化。在

TL;DR

staticmethod返回可调用的描述符,但其__get__方法返回自身的未绑定版本。property创建一个不可压缩的描述符,其__get__方法调用属性的getter。使用结果属性将尝试将self传递给不接受它的静态方法。在

相关问题 更多 >

    热门问题