python抽象基类可以从C扩展继承吗?

编程入门 行业动态 更新时间:2024-10-17 23:27:54
本文介绍了python抽象基类可以从C扩展继承吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

当我有一个继承自gevent.Greenlet的抽象基类时(似乎继承自C扩展模块greenlet: github/python-greenlet/greenlet ),则实现该类的类不会引发任何有关未实现方法的abc错误.

It seems as if that when I have an abstract base class that inherits from gevent.Greenlet (which inherits from the C extension module greenlet: github/python-greenlet/greenlet) then classes that implement it do not raise any of the abc errors about unimplemented methods.

class ActorBase(gevent.Greenlet): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): print "foo" class ActorBaseTest(ActorBase): def bar(self): print "bar" abt = ActorBaseTest() # no errors!

如果我从 object 继承,它会按预期失败:

If I inherit from object it fails as expected:

class ActorBase(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): print "foo" class ActorBaseTest(ActorBase): def bar(self): print "bar" >>> abt = ActorBaseTest() Traceback (most recent call last): File "/home/dw/.virtualenvs/prj/local/lib/python2.7/site-packages/IPython/core/interactiveshell.py", line 2827, in run_code exec code_obj in self.user_global_ns, self.user_ns File "<ipython-input-6-d67a142e7297>", line 1, in <module> abt = ActorBaseTest() TypeError: Can't instantiate abstract class ActorBaseTest with abstract methods foo

实现此功能的正确方法是什么?

What is the right way to implement this functionality?

推荐答案

问题的原因是它是 object .__ new __ 方法,该方法检查抽象类的实例化,在本例中为 object .__ new __ 不会被调用: gevent.Greenlet 继承自 greenlet.greenlet ,而 greenlet.greenlet 是C扩展类型,其__new __ 实现在任何时候都不会调用 object .__ new __ (请参见 greenlet C源代码中的 green_new 函数.

The cause of your problem is that it's the object.__new__ method that does the check for instantiation of an abstract class, and in this case object.__new__ isn't being invoked: gevent.Greenlet inherits from greenlet.greenlet, and greenlet.greenlet is a C extension type whose __new__ implementation doesn't call object.__new__ at any point (see the green_new function in the greenlet C source).

通过将实现其自己的 __ new __ 方法的其他一些内置类型的子类化,可以看到相同的效果,而不必回头引用 object .__ new __ ( float 类型).但是,该问题并不只限于C扩展类型:您还可以使用纯Python类型来复制它.考虑下面的代码:

You can see the same effect by subclassing some of the other builtin types that implement their own __new__ method and don't refer back to object.__new__ (the float type, for example). The issue is not particular to C extension types, though: you can also replicate it with pure Python types. Consider the code below:

import abc class A(object): def __new__(cls): # self = object.__new__(cls) return 42 class B(A): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): pass b = B() # No exception.

类 B 已正确注册为抽象类(内部,其 Py_TPFLAGS_IS_ABSTRACT 位在 tp_flags 字段中设置),但 object .__ new __ 不会被调用,因此实例化 B 时不会出错.但是,如果取消注释 A 中的 self = object .__ new __(cls)方法调用,则会在实例化时看到预期的错误.

The class B is correctly registered as an abstract class (internally, its Py_TPFLAGS_IS_ABSTRACT bit is set in the tp_flags field), but object.__new__ is never called, so there's no error when B is instantiated. However, if you uncomment the self = object.__new__(cls) method call in A, you'll see the expected error on instantiation.

就实现此目标的正确方法"而言,不幸的是,我认为正确的方法是修复 greenlet 类型,以便其 __ new __ 方法调用对象.__new __ .我猜您可以在 ActorBase 中添加 __ new __ 方法,以显式调用基类 __ new __ 和 object .__ new __ (并丢弃后者的结果),但我认为这是一个丑陋的解决方法,而不是正确的方法".(最重要的是,它不起作用.我得到 TypeError:object .__ new __(ActorBase)不安全,请从 object使用greenlet.greenlet .__ new __().__ new __ 调用.)我已经打开了 issue 绿色跟踪器.

As far as the 'right way' to implement this, unfortunately I think the right way is to fix the greenlet type so that its __new__ method calls object.__new__. I guess you could add a __new__ method to ActorBase that explicitly calls both the base class __new__ and object.__new__ (and throws away the result of the latter), but I'd consider that an ugly workaround rather than the 'right way'. ( And on top of that, it doesn't work. I get TypeError: object.__new__(ActorBase) is not safe, use greenlet.greenlet.__new__() from the object.__new__ call.) I've opened an issue on the greenlet tracker.

这个问题似乎有点耳熟,我只是对思想特质来源进行了一些研究,定义了一个用C实现的 CHasTraits 类,该类确实可以很好地与ABC一起使用.它的 __ new __ 方法是这样开始的(注释来自原始来源,而不是我的):

This problem seemed somewhat familiar, and I just did some digging into the Enthought Traits source, which defines a CHasTraits class implemented in C which does play nicely with ABCs. And its __new__ method starts like this (comments are from the original source, not mine):

PyObject * has_traits_new ( PyTypeObject * type, PyObject * args, PyObject * kwds ) { // Call PyBaseObject_Type.tp_new to do the actual construction. // This allows things like ABCMeta machinery to work correctly // which is implemented at the C level. has_traits_object * obj = (has_traits_object *) PyBaseObject_Type.tp_new(type, empty_tuple, empty_dict);

因此,也许长期的解决方案是说服 greenlet 员工做类似的事情.

So perhaps the long-term solution is to persuade the greenlet folks to do something similar.

更多推荐

python抽象基类可以从C扩展继承吗?

本文发布于:2023-08-01 12:36:16,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1268422.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:抽象   python

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!