Python 2与3兼容的抽象属性实现:替代已弃用的abc.abstractproperty
兼容Python 2和3的抽象属性实现方案
你遇到的问题确实是Python 2和3在抽象属性处理上的差异导致的——Python 2的abc.ABCMeta无法识别叠加了@property和@abc.abstractmethod的属性为抽象方法,而Python 3则已经修复了这个逻辑。
要实现兼容两个版本的抽象属性,我们可以写一个适配性的装饰器,自动根据Python版本选择对应的实现方式,既不用弃用的abc.abstractproperty(在Py3中),又能在Py2中正常工作。
解决方案代码
import abc from future.utils import with_metaclass def abstract_property(func): # 检查当前Python版本是否有abc.abstractproperty(Python 2存在,Python 3已弃用) if hasattr(abc, 'abstractproperty'): return abc.abstractproperty(func) else: # Python 3+ 使用@property包裹@abstractmethod的标准写法 return property(abc.abstractmethod(func)) class Base(with_metaclass(abc.ABCMeta, object)): @abstract_property def x(self): raise NotImplementedError class C(Base): pass # 测试实例化,两个版本都会抛出TypeError try: C() except TypeError as e: print(e)
为什么这个方案有效?
- Python 2环境:直接使用官方提供的
abc.abstractproperty,它会把属性标记为抽象的,ABCMeta能正确识别,实例化未实现该属性的子类时会抛出TypeError。 - Python 3环境:遵循官方推荐的
@property + @abc.abstractmethod组合写法,既避免了使用已弃用的API,又能让ABCMeta正确识别抽象属性。
为什么你的原代码在Python 2中无效?
Python 2的abc.ABCMeta只会检查直接被@abc.abstractmethod装饰的方法是否在子类中实现。当你先用@abstractmethod装饰再用@property包装时,property对象会覆盖掉abstractmethod的标记,导致ABCMeta无法识别这是一个抽象属性,因此允许实例化未实现x的子类C。
内容的提问来源于stack exchange,提问作者sfinkens
相关产品推荐
相关产品推荐

