在python3.6中,我试图在AbstractBaseClass中定义一个属性;我的第一次尝试是这样的(后来我发现我可以省略@staticmethod
):
class AnAbstractClass(ABC):
@property
@staticmethod
@abstractmethod
def my_property():
pass
据我所知,@staticmethod
修饰符不返回可调用的,而是返回不同的值。
(我怀疑这也会导致mypy在代码中的返回值类型上引发错误,但是我无法在较小的代码示例中重现该问题)。在
这是怎么回事?在
要理解为什么收到警告,您需要对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
创建了一个相当普通的类方法,但它与元类^{你的代码似乎遵循了这条禁令。事实上,
abstractmethod
与你的警告没有任何关系,但无论如何在这里提到它似乎是个好主意。在staticmethod
返回一个可调用的方法,该方法绕过常规绑定行为来创建一个不关心从哪个类或实例调用它的方法。特别是,使用staticmethod.__get__
绑定的方法将把它的参数传递给函数,而不是先在self
前面加上__get__
基本上只返回原始函数)。您可以想象,对于希望接收self
参数的对象来说,这将是一个问题,比如属性的setter。在与
abstractmethod
和staticmethod
不同,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
参数并允许正常方法绑定发生。在property
和staticmethod
都能很好地使用abstractmethod
(只要先应用abstractmethod
),因为它不会对原始函数进行任何更改。实际上,abstractmethod
的文档特别提到,property
抽象的getter、setter或deleter使整个属性抽象化。在TL;DR
staticmethod
返回可调用的描述符,但其__get__
方法返回自身的未绑定版本。property
创建一个不可压缩的描述符,其__get__
方法调用属性的getter。使用结果属性将尝试将self
传递给不接受它的静态方法。在相关问题 更多 >
编程相关推荐