我正在使用Python类,并且我没有对其声明的写入权限。
如何在不修改类声明的情况下将自定义方法(例如 __str__
)附加到从该类创建的对象中?
编辑:
谢谢你的所有答案。我尝试了所有这些,但他们没有解决我的问题。这是一个最小的例子,我希望能澄清这个问题。我使用swig来包装C ++类,目的是覆盖swig模块返回的一个对象的__str__
函数。我使用cmake来构建示例:
test.py
import example
ex = example.generate_example(2)
def prnt(self):
return str(self.x)
#How can I replace the __str__ function of object ex with prnt?
print ex
print prnt(ex)
example.hpp
struct example
{
int x;
};
example generate_example(int x);
example.cpp
#include "example.hpp"
#include <iostream>
example generate_example(int x)
{
example ex;
ex.x = x;
return ex;
}
int main()
{
example ex = generate_example(2);
std::cout << ex.x << "\n";
return 1;
}
example.i
%module example
%{
#include "example.hpp"
%}
%include "example.hpp"
的CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
find_package(PythonLibs)
include_directories(${PYTHON_INCLUDE_PATH})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set_source_files_properties(example.i PROPERTIES CPLUSPLUS ON)
swig_add_module(example python example.i example)
swig_link_libraries(example ${PYTHON_LIBRARIES})
if(APPLE)
set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -flat_namespace")
endif(APPLE)
要构建并运行test.py,请复制目录中的所有文件,并在该目录中运行
cmake .
make
python test.py
这导致以下输出:
<example.example; proxy of <Swig Object of type 'example *' at 0x10021cc40> >
2
正如您所看到的,Swig对象具有自己的 str 功能,这就是我想要覆盖的内容。
答案 0 :(得分:20)
如果您创建了一个包装类,这将适用于任何其他类,无论是内置还是非内置类。这称为“包含和委托”,它是继承的常见替代方法:
class SuperDuperWrapper(object):
def __init__(self, origobj):
self.myobj = origobj
def __str__(self):
return "SUPER DUPER " + str(self.myobj)
def __getattr__(self,attr):
return getattr(self.myobj, attr)
__getattr__
方法会将SuperDuperWrapper对象上的所有未定义属性请求委托给包含的myobj对象。事实上,考虑到Python的动态类型,你可以使用这个类来SuperDuper'包装任何东西:
s = "hey ho!"
sds = SuperDuperWrapper(s)
print sds
i = 100
sdi = SuperDuperWrapper(i)
print sdi
打印:
SUPER DUPER hey ho!
SUPER DUPER 100
在您的情况下,您将从无法修改的函数中获取返回的对象,并将其包装在您自己的SuperDuperWrapper中,但您仍然可以像访问基础对象一样访问它。
print sds.split()
['hey', 'ho!']
答案 1 :(得分:3)
>>> class C(object):
... pass
...
>>> def spam(self):
... return 'spam'
...
>>> C.__str__ = spam
>>> print C()
spam
它不适用于使用__slots__
的类。
答案 2 :(得分:3)
创建一个子类。例如:
>>> import datetime
>>> t = datetime.datetime.now()
>>> datetime.datetime.__str__ = lambda self: 'spam'
...
TypeError: cant set attributes of built-in/extension type 'datetime.datetime'
>>> t.__str__ = lambda self: 'spam'
...
AttributeError: 'datetime.datetime' object attribute '__str__' is read-only
>>> class mydate(datetime.datetime):
def __str__(self):
return 'spam'
>>> myt = mydate.now()
>>> print t
2009-09-05 13:11:34.600000
>>> print myt
spam
答案 3 :(得分:2)
这是another question的答案:
import types
class someclass(object):
val = "Value"
def some_method(self):
print self.val
def some_method_upper(self):
print self.val.upper()
obj = someclass()
obj.some_method()
obj.some_method = types.MethodType(some_method_upper, obj)
obj.some_method()
答案 4 :(得分:1)
请注意,使用Alex的子类构思,您可以使用“from
... import
... as
”来帮助自己更多:
from datetime import datetime as datetime_original
class datetime(datetime_original):
def __str__(self):
return 'spam'
所以现在该类具有标准名称,但行为不同。
>>> print datetime.now()
'spam'
当然,这可能很危险......