2014-09-17 17 views
8

dưới đây là cách triển khai đơn giản của mẫu khách truy cập trong C++. Ist nó có thể thực hiện một cái gì đó như thế này trong Python?Mẫu khách truy cập trong python

Tôi cần nó, bởi vì tôi sẽ chuyển đối tượng từ mã C++ vào một hàm bằng Python. Ý tưởng của tôi là triển khai một khách truy cập bằng Python để tìm ra loại Object.

My 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); 
} 

Trả lời

12

Các mẫu người truy cập có thể được thực hiện bằng Python, tôi sử dụng nó để thực hiện một giao diện sạch giữa của tôi lớp dữ liệu và bản trình bày. Lớp dữ liệu có thể xác định thứ tự của dữ liệu. và các lớp trình bày đơn giản là in/định dạng nó:

Trong module dữ liệu của tôi, tôi có:

class visited(object): 
    .... 
    def accept(self, visitor): 
     visitor.visit(self) 
     for child in self.children(): 
      child.accept(visitor) 

class typeA(visited): 
    .... 

Tất cả các lớp dữ liệu của tôi kế thừa từ này đã đến thăm lớp, và lớp đến thăm cũng cho thấy một số chức năng đơn giản để cơ bản dữ liệu tất cả các đối tượng của tôi cần ví dụ tên, cha mẹ, vv và các phương pháp quản lý danh sách con - được hiển thị theo phương pháp children() được sử dụng ở trên. mỗi lớp phụ sẽ xây dựng dữ liệu riêng của chúng, có các thuộc tính riêng của chúng và thậm chí cả lớp con riêng của chúng - được thêm vào danh sách trẻ em được duy trì bởi lớp siêu truy cập.

lớp khách truy cập của tôi là như thế này:

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""" 
      ... 

các _find_data_instance là một số mã mà xây dựng hoặc tìm thấy một thể hiện của một trong những trường hợp dữ liệu của tôi. Trong trường hợp của tôi, tất cả các lớp dữ liệu của tôi có một hàm khởi tạo lấy một số objectId và trả về, và đối tượng khách truy cập biết lớp dữ liệu nào sẽ sử dụng.

+0

Cảm ơn sự giúp đỡ của bạn. – bogdan

+0

Không biết phiên bản Python nào bạn sử dụng, nhưng trong phiên bản 2.7.6, cuộc gọi 'instance' không tồn tại. Bạn nên sử dụng 'isinstance' – Matthias

+0

@Matthias - tốt bắt - sẽ rất vui khi bạn đưa điều đó vào làm đề xuất chỉnh sửa –

3

Bạn thể thực hiện điều này bằng Python, nhưng có thực sự không cần đến. Python là một ngôn ngữ động, diễn giải, có nghĩa là thông tin kiểu có thể dễ dàng có sẵn khi chạy.

Vì vậy, ví dụ trên của bạn có thể đơn giản như

class C1(object): 
    pass 

class C2(object): 
    pass 

l = [C1(), C2()] 
if __name__=="__main__": 
    for element in l: 
     print type(element) 

mà sẽ mang lại:

<class '__main__.C1'> 
<class '__main__.C2'> 
+0

Cảm ơn sự giúp đỡ của bạn! Tôi đã chấp nhận câu trả lời của bạn, nhưng Tony thì chi tiết hơn một chút. – bogdan

8

Bạn có thể sử dụng trang trí để có được những gì bạn muốn. Sao chép một ví dụ từ blog này:

class Lion: pass 
class Tiger: pass 
class Bear: pass 

class ZooVisitor: 
    @visitor(Lion) 
    def visit(self, animal): 
     return "Lions" 

    @visitor(Tiger) 
    def visit(self, animal): 
     return "tigers" 

    @visitor(Bear) 
    def visit(self, animal): 
     return "and bears, oh my!" 

animals = [Lion(), Tiger(), Bear()] 
visitor = ZooVisitor() 
print(', '.join(visitor.visit(animal) for animal in animals)) 
# Prints "Lions, tigers, and bears, oh my!" 

và mã cho @visitor trang trí (trong trường hợp liên kết đi chết):

# A couple helper functions first 

def _qualname(obj): 
    """Get the fully-qualified name of an object (including module).""" 
    return obj.__module__ + '.' + obj.__qualname__ 

def _declaring_class(obj): 
    """Get the name of the class that declared an object.""" 
    name = _qualname(obj) 
    return name[:name.rfind('.')] 

# Stores the actual visitor methods 
_methods = {} 

# Delegating visitor implementation 
def _visitor_impl(self, arg): 
    """Actual visitor method implementation.""" 
    method = _methods[(_qualname(type(self)), type(arg))] 
    return method(self, arg) 

# The actual @visitor decorator 
def visitor(arg_type): 
    """Decorator that creates a visitor method.""" 

    def decorator(fn): 
     declaring_class = _declaring_class(fn) 
     _methods[(declaring_class, arg_type)] = fn 

     # Replace all decorated methods with _visitor_impl 
     return _visitor_impl 

    return decorator 

viết blog liên quan (người đầu tiên đã có vẻ là xuống): https://chris-lamb.co.uk/posts/visitor-pattern-in-python

EDIT:

obj.__qualname__ không khả dụng cho đến khi Python 3.3, vì vậy chúng ta phải sử dụng một hack cho phiên bản thấp hơn: -

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 

Thật không may là giải pháp trên không làm việc cho các phiên bản python dưới 3.3, như các phương pháp là chức năng vẫn thường xuyên khi truyền cho một trang trí. Bạn có thể thử sử dụng cả trình trang trí lớp và phương thức, xem Can a Python decorator of an instance method access the class?.

Các vấn đề liên quan