python:如何重写静态属性?

2024-04-29 08:08:41 发布

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

我有一个基类和一个派生类,它们都有一个同名的静态方法。在保持名称相同的情况下,是否可以同时公开这两个名称?这将编译,但在导入模块时引发异常

struct Base
{
    static std::string say_hi() { return "Hi"; }
};

struct Derived : public Base
{
    static std::string say_hi() { return "Hello"; }
};

BOOST_PYTHON_MODULE(HelloBoostPython)
{
    namespace py = boost::python;

    py::class_<Base>("Base").add_static_property("say_hi", &Base::say_hi);

    py::class_<Derived, py::bases<Base>>("Derived").add_static_property("say_hi", &Derived::say_hi);
}

进口时:

>>> import HelloBoostPython
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: initialization of HelloBoostPython raised unreported exception

将最后一行更改为其他名称是可行的,但我更希望覆盖基类的属性:

py::class_<Derived, py::bases<Base>>("Derived").add_static_property("say_hello", &Derived::say_hi);

这是可行的,但我得到的是类方法而不是属性:

BOOST_PYTHON_MODULE(HelloBoostPython)
{
    namespace py = boost::python;

    py::object base = py::class_<Base>("Base");
    base.attr("say_hi") = Base::say_hi;

    py::object derived = py::class_<Derived, py::bases<Base>>("Derived");
    derived.attr("say_hi") = Derived::say_hi;
}

这将为我提供属性,但如果静态方法不是常量,则在一般情况下不起作用:

BOOST_PYTHON_MODULE(HelloBoostPython)
{
    namespace py = boost::python;

    py::object base = py::class_<Base>("Base");
    base.attr("say_hi") = Base::say_hi();

    py::object derived = py::class_<Derived, py::bases<Base>>("Derived");
    derived.attr("say_hi") = Derived::say_hi();
}


Tags: py名称baseobjectstatichiclassattr
2条回答

看看Boost Python是如何公开静态属性的,以及它在Python中的行为,看起来这是Boost Python中的一个bug

当我尝试导入有问题的示例时,出现以下错误:

>>> import HelloBoostPython
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>

无法设置该属性,因为派生类中存在冲突Derived类首先从Base继承say_hi属性,然后尝试定义它自己的属性。这可以通过将Derived类中的say_hi更改为say_hello来轻松验证,正如作者所做的那样:

py::class_<Derived, py::bases<Base>>("Derived").add_static_property("say_hello", &Derived::say_hi);

然后我们可以看到以下数据描述符help(HelloBoostPython.Derived)

    class Derived(Base)
...
...
     |                                     
     |  Data descriptors defined here:
     |
     |  say_hello
     |
     |                                     
     |  Data and other attributes defined here:
     |
     |  __instance_size__ = 24
     |
     |                                     
     |  Data descriptors inherited from Base:
     |
     |  say_hi
...
...

但是,当我们在python中定义类似的内容时:

class Base(object):

    def get_say_hi(self):
        return "hi"

    say_hi = property(get_say_hi)

class Derived(Base):

    def get_say_hi(self):
        return "hello"

    say_hi = property(get_say_hi)

我们可以看到这里只有say_hi中定义的Derived

class Derived(Base)
...
...
 |                                     
 |  Data descriptors defined here:
 |
 |  say_hi
 |
 |                                     
 |  Data descriptors inherited from Base:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
(END)

Derived中删除say_hi后:

class Base(object):

    def get_say_hi(self):
        return "hi"

    say_hi = property(get_say_hi)

class Derived(Base):
    None

我们从Base继承它,然后:

class Derived(Base)
...
...
 |                                     
 |  Data descriptors inherited from Base:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  say_hi
(END)

问题是,当Boost.Python的元类试图声明和设置Derived.say_hi时,它会解析为Base.say_hi.__set__,因为它是从Base继承的现有类描述符。一个解决方案是自己将属性绑定到Derived类。例如

namespace py = boost::python;

py::class_<Base>("Base").add_static_property("say_hi", &Base::say_hi);

py::class_<Derived, py::bases<Base>> Derived_("Derived");

PyDict_SetItemString(
    py::downcast<PyTypeObject>(Derived_.ptr())->tp_dict,
    "say_hi",
    Derived_.attr("__base__").attr("__dict__")["say_hi"].attr("__class__")(
        py::make_function(&Derived::say_hi)
    ).ptr()
);

这样say_hi作为Boost.Python.StaticProperty实例直接绑定到Derived类。现在输入以下代码:

print(Base().say_hi, Base.say_hi, Derived().say_hi, Derived.say_hi)

将正确打印:

Hi Hi Hello Hello

相关问题 更多 >