python中的访问者模式 这是C++中访问者模式的一种简化实现。有可能在Python中实现类似的东西吗 我需要它,因为我将把对象从C++代码传递到Python中的函数。我的想法是用Python实现一个访问者,以找出对象的类型 我的C++代码: #include <iostream> #include <string> class t_element_base { public: virtual void accept( class t_visitor &v ) = 0; }; class t_element_deriv_one: public t_element_base { public: void accept( t_visitor &v ); std::string t_element_deriv_one_text() { return "t_element_deriv_one"; } }; class t_element_deriv_two: public t_element_base { public: void accept( t_visitor &v ); std::string t_element_deriv_two_text() { return "t_element_deriv_one"; } }; class t_visitor { public: void visit( t_element_deriv_one& e ){ std::cout << e.t_element_deriv_one_text() << std::endl; } void visit( t_element_deriv_two& e ){ std::cout << e.t_element_deriv_two_text() << std::endl; } }; void t_element_deriv_one::accept( t_visitor &v ) { v.visit( *this ); } void t_element_deriv_two::accept( t_visitor &v ) { v.visit( *this ); } int main ( void ) { t_element_base* list[] = { new t_element_deriv_one(), new t_element_deriv_two() }; t_visitor visitor; for( int i = 0; i < 2; i++ ) list[ i ]->accept( visitor ); } #包括 #包括 类t_元素_基 { 公众: 虚拟无效接受(t_类访问者&v)=0; }; 类t_元素_deriv_one:公共t_元素_base { 公众: 无效接受(t_访客和v); std::string t_element_deriv_one_text() { 返回“t_element_deriv_one”; } }; 第二类t_元素:公共t_元素基 { 公众: 无效接受(t_访客和v); std::string t_element_deriv_two_text() { 返回“t_element_deriv_one”; } }; t类访客 { 公众: voidvisit(t_element_derivu one&e){std::cout
您可以在Python中实现这一点,但实际上没有必要。Python是一种动态的解释语言,这意味着类型信息在运行时很容易获得 所以你上面的例子可以简单到python中的访问者模式 这是C++中访问者模式的一种简化实现。有可能在Python中实现类似的东西吗 我需要它,因为我将把对象从C++代码传递到Python中的函数。我的想法是用Python实现一个访问者,以找出对象的类型 我的C++代码: #include <iostream> #include <string> class t_element_base { public: virtual void accept( class t_visitor &v ) = 0; }; class t_element_deriv_one: public t_element_base { public: void accept( t_visitor &v ); std::string t_element_deriv_one_text() { return "t_element_deriv_one"; } }; class t_element_deriv_two: public t_element_base { public: void accept( t_visitor &v ); std::string t_element_deriv_two_text() { return "t_element_deriv_one"; } }; class t_visitor { public: void visit( t_element_deriv_one& e ){ std::cout << e.t_element_deriv_one_text() << std::endl; } void visit( t_element_deriv_two& e ){ std::cout << e.t_element_deriv_two_text() << std::endl; } }; void t_element_deriv_one::accept( t_visitor &v ) { v.visit( *this ); } void t_element_deriv_two::accept( t_visitor &v ) { v.visit( *this ); } int main ( void ) { t_element_base* list[] = { new t_element_deriv_one(), new t_element_deriv_two() }; t_visitor visitor; for( int i = 0; i < 2; i++ ) list[ i ]->accept( visitor ); } #包括 #包括 类t_元素_基 { 公众: 虚拟无效接受(t_类访问者&v)=0; }; 类t_元素_deriv_one:公共t_元素_base { 公众: 无效接受(t_访客和v); std::string t_element_deriv_one_text() { 返回“t_element_deriv_one”; } }; 第二类t_元素:公共t_元素基 { 公众: 无效接受(t_访客和v); std::string t_element_deriv_two_text() { 返回“t_element_deriv_one”; } }; t类访客 { 公众: voidvisit(t_element_derivu one&e){std::cout,python,visitor,Python,Visitor,您可以在Python中实现这一点,但实际上没有必要。Python是一种动态的解释语言,这意味着类型信息在运行时很容易获得 所以你上面的例子可以简单到 class C1(object): pass class C2(object): pass l = [C1(), C2()] if __name__=="__main__": for element in l: print type(element) 这将产生: <class '__main__.
class C1(object):
pass
class C2(object):
pass
l = [C1(), C2()]
if __name__=="__main__":
for element in l:
print type(element)
这将产生:
<class '__main__.C1'>
<class '__main__.C2'>
访问者模式可以用Python实现,我使用它在我的数据和表示层之间实现一个干净的接口。数据层可以确定数据的顺序。表示层只需打印/格式化它: 在我的数据模块中,我有:
class visited(object):
....
def accept(self, visitor):
visitor.visit(self)
for child in self.children():
child.accept(visitor)
class typeA(visited):
....
我的所有数据类都继承自这个访问过的类,访问过的类还为我的所有对象所需的基本数据(例如名称、父对象等)公开了一些简单的函数,以及管理子列表的方法,子列表由children()公开
上面使用的方法。每个子类都将构建自己的数据,拥有自己的属性,甚至可能有自己的子类-这些子类将添加到访问的超类维护的子类列表中
我的访客课是这样的:
class visitor(object):
def __init__(self, obj_id):
data_obj = _find_data_instance( obj_id )
data_obj.accept(self)
def visit( self, data_obj):
if isinstance(data_obj, typeA):
self.visit_typeA( dataobj)
def visit_typeA(self, dataobj):
"""Formats the data for typeA"""
...
\u find\u data\u instance
是一些构建或查找我的一个数据实例实例的代码。在我的情况下,我的所有数据类都有一个构造函数,它接受一个objectId
并返回,访问者对象知道要使用哪个数据类。您可以使用decorator来获取所需的内容。从中复制一个示例:
以及@visitor装饰器的代码(以防链接失效):
相关博客(第一个似乎已经关闭):
编辑:
obj.\uuuuu qualname\uuuu
在Python 3.3之前不可用,因此我们必须对较低版本使用hack:-
def _qualname(obj):
"""Get the fully-qualified name of an object (including module)."""
if hasattr(obj, '__qualname__'):
qualname = obj.__qualname__
else:
qualname = str(obj).split(' ')[1]
return obj.__module__ + '.' + qualname
不幸的是,上述解决方案不适用于3.3以下的python版本,因为方法在传递给装饰器时仍然是常规函数。您可以尝试同时使用类装饰器和方法装饰器,请参见。如果有人认为它有用,我在python 2中使用内省获得了以下版本的
@visitor
:
_visitors = {}
def visitor(arg_type):
"A @visitor decorator"
def decorated(fn):
import inspect
stack = inspect.currentframe()
class_name = stack.f_back.f_code.co_name
full_name = fn.__module__ + '.' + class_name + '.' + fn.__name__
_visitors[(full_name, arg_type)] = fn
def _visitor_impl(self, arg, *rest, **kwargs):
full_name = fn.__module__ + '.' + self.__class__.__name__ + '.' + fn.__name__
assert (full_name, arg.__class__) in _visitors, "Can't find visitor in {} for {}".format(full_name, arg.__class__.__name__)
method = _visitors[(full_name, arg.__class__)]
return method(self, arg, *rest, **kwargs)
return _visitor_impl
return decorated
首先
- 什么是面向对象编程?它是对单个参数的动态调度(java&C++中的隐式
)this
- 访问者模式的作用是什么:它试图在这些语言上模拟双重分派,因此它使用两个类作为解决方法
感谢您的帮助。我不知道您使用的是哪一个Python版本,但在2.7.6版本中,
实例
调用不存在。您应该使用isinstance
@Matthias-很好的捕获-如果您将其作为编辑建议,我会很高兴的谢谢您的帮助!我会接受您的答案,但Tony的答案有点错误我们很详细。
def _qualname(obj):
"""Get the fully-qualified name of an object (including module)."""
if hasattr(obj, '__qualname__'):
qualname = obj.__qualname__
else:
qualname = str(obj).split(' ')[1]
return obj.__module__ + '.' + qualname
_visitors = {}
def visitor(arg_type):
"A @visitor decorator"
def decorated(fn):
import inspect
stack = inspect.currentframe()
class_name = stack.f_back.f_code.co_name
full_name = fn.__module__ + '.' + class_name + '.' + fn.__name__
_visitors[(full_name, arg_type)] = fn
def _visitor_impl(self, arg, *rest, **kwargs):
full_name = fn.__module__ + '.' + self.__class__.__name__ + '.' + fn.__name__
assert (full_name, arg.__class__) in _visitors, "Can't find visitor in {} for {}".format(full_name, arg.__class__.__name__)
method = _visitors[(full_name, arg.__class__)]
return method(self, arg, *rest, **kwargs)
return _visitor_impl
return decorated
class A: pass
class B: pass
class visitor:
def __init__(self, f):
self.f = f
self.cases = {}
def case(self, type1, type2):
def call(fun):
self.cases[(type1, type2)] = fun
return call
def __call__(self, arg1, arg2):
fun = self.cases[type(arg1), type(arg2)]
return fun(arg1, arg2)
@visitor
def f(x, y): pass
@f.case(A, int)
def fun1(a, b):
print("called with A and int")
@f.case(B, str)
def fun2(a, b):
print("called with B and string")
f(A(), 5)
f(B(), "hello")