要了解您收到警告的原因,您需要了解一下装饰器和描述符。
装饰器
装饰器是可调用的,它替换它正在装饰的东西,并将其分配给命名空间中的相同名称。通常,装饰器用于函数和类以添加一些功能,例如类型检查或线程或其他东西,但实际上它们可以返回任何东西。
由于装饰器的输出不必与输入的类型相同,也不必执行任何相同的处理,因此装饰器的顺序非常重要。装饰器的应用顺序是从最接近函数的那个到列表顶部的那个。在您的情况下,abstractmethod
,然后staticmethod
,然后property
。
描述符
描述符定义了一个相当复杂的协议,允许使用它们提供的绑定行为来定制对象。出于您的目的,您需要知道函数是描述符,并且将它们放入类对象中使用 this。当您在该类的实例上调用该类中定义的任何描述符时,描述符协议使用描述符的__get__
方法将该描述符绑定到该实例。描述符本身甚至不必是可调用的, 的返回值也不是__get__
,尽管在大多数情况下它应该是。对于函数,返回一个自动作为第一个位置参数__get__
传递的闭包。self
例如,给定一个A
具有方法的类def b(self, arg):
,以及该类的一个实例,称为a
,doinga.b(arg)
变成A.b.__get__(a, A)(arg)
。因此,虽然b
定义为具有两个位置参数,但在实例上调用时只需要显式传入一个。但是,当你b
通过类调用时,例如,A.b(a, arg)
它只是一个普通的函数,你需要手动传入所有参数,包括self
。
把它们放在一起
abstractmethod
,property
并且staticmethod
都是返回可调用描述符对象的装饰器。但是,__get__
它们的描述符的方法与普通函数对象的方法有些不同__get__
。
abstractmethod
创建了一个相当普通的类方法,但它与元类交互ABCMeta
,因此当您尝试使用抽象方法实例化一个类时会遇到各种有用的错误。它不会以任何方式修改结果预期的输入参数。事实上,文档暗示所有副作用可能与元类有关,并且原始输入只是通过。这里唯一要真正记住的是
与其他方法描述符结合应用时abstractmethod()
,应作为最内层的装饰器应用,如下使用示例所示: ...
您的代码似乎遵循该禁令。实际上abstractmethod
与您的警告无关,但无论如何在这里提及它似乎是个好主意。
staticmethod
返回一个绕过正常绑定行为的可调用对象,以创建一个不关心从哪个类或实例调用它的方法。特别是,绑定 using 的方法staticmethod.__get__
会将其参数传递给您的函数,而不是self
先添加(即,__get__
基本上只是返回您的原始函数)。你可以想象这对于期望接收self
参数的东西来说是个问题,比如属性的设置器。
与abstractmethod
and不同staticmethod
,property
它创建一个数据描述符。这意味着它返回一个同时具有__get__
绑定和__set__
绑定(以及__del__
绑定)的对象。属性的__get__
方法与普通函数的方法非常相似__get__
,但专门应用于 getter 函数。property
非常关心从哪个实例调用它,因为您当然希望不同的实例具有属性包装的属性的不同值。
因此,您的代码中的内容staticmethod
后面是property
. 第一个装饰器返回一个在绑定时不self
添加到其参数列表的函数,而第二个装饰器期望有一个。没有什么可以阻止您调用装饰器,但是 IDE 警告告诉您,您不会成功调用结果对象。如果您尝试访问my_property
的具体实现AnyAbstractClass
,您可能会收到一条不接受任何位置参数的TypeError
通知,但给出了一个,因为它会添加到不接受任何参数的静态方法的参数列表中。my_property
property.__get__
self
请记住,申请staticmethod
结果property
也对您没有太大帮助。property
实例根本不可调用。它完全通过它的__get__
,__set__
和__del__
方法运行,同时staticmethod
假设你传入一个可调用对象。
解决方案
正如你已经正确发现的那样staticmethod
,property
不要混合得很好。就其本质而言,属性应该始终了解它所操作的实例。这样做的正确方法是添加一个self
参数并允许进行正常的方法绑定。
两者都property
可以staticmethod
很好地使用abstractmethod
(只要abstractmethod
先应用),因为它实际上不会改变您的原始功能。事实上,文档abstractmethod
特别提到抽象的 getter、setter 或 deleterproperty
使整个属性抽象。
TL;博士
staticmethod
返回一个可调用的描述符,但其__get__
方法返回其自身的未绑定版本。property
创建一个不可调用的描述符,其__get__
方法调用属性的 getter。使用结果属性将尝试传递self
给不接受它的静态方法。