2014-09-17 12 views
8

tutaj jest uproszczona implementacja wzorca gościa w C++. Czy możliwe jest zaimplementowanie czegoś takiego w Pythonie?Wzór użytkownika w pytonie

Potrzebuję tego, ponieważ przejdę Objects z kodu C++ do funkcji w Pythonie. Moim pomysłem było zaimplementowanie gościa w Pythonie, aby dowiedzieć się jaki jest typ Obiektu.

Moje C++ Kod:

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

Odpowiedz

12

odwiedzający mogą zostać wdrożone w Pythonie, używam go wdrożyć przejrzysty interfejs między moim warstwa danych i prezentacji. Warstwa danych może określać kolejność danych. a warstwa prezentacji po prostu wypisuje/formaty go:

W moim moduł danych mam:

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

class typeA(visited): 
    .... 

Wszystkie moje klas danych dziedziczą ten odwiedził klasę i odwiedził klasa naraża również proste funkcje podstawowe dane wszystkie moje obiekty potrzebują np nazwisko, rodzic itp. oraz metody zarządzania listą potomną - która jest wyeksponowana za pomocą metody children() zastosowanej powyżej. każda z podklas będzie budować własne dane, posiadać własne właściwości, a może nawet własną klasę potomną - które zostaną dodane do listy dzieci przez odwiedzoną super klasę.

Moja klasa gość jest tak:

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

_find_data_instance jest jakiś kod, który buduje lub stwierdzi wystąpienie jednej z moich wystąpień danych. W moim przypadku wszystkie moje klasy danych mają konstruktor, który pobiera objectId i zwraca, a obiekt odwiedzający wie, jakiej klasy danych użyć.

+0

Dziękuję za pomoc. – bogdan

+0

Nie wiem, której wersji Python używasz, ale w wersji 2.7.6 wywołanie 'instance' nie istnieje. Powinieneś użyć 'isinstance'a – Matthias

+0

@Matthias - dobry połów - byłby szczęśliwy, gdybyś wstawił to jako sugestię edycji –

3

Ty mógłby zaimplementować to w Pythonie, ale naprawdę nie ma takiej potrzeby. Python jest językiem dynamicznym, interpretowanym, co oznacza, że ​​informacje o typie są łatwo dostępne w środowisku wykonawczym.

Więc Powyższy przykład może być tak proste, jak

class C1(object): 
    pass 

class C2(object): 
    pass 

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

który przyniesie:

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

Dziękuję za pomoc! Przyjąłbym twoją odpowiedź, ale Tony był trochę bardziej szczegółowy. – bogdan

8

Możesz użyć dekoratorów, aby uzyskać to, co chcesz. Kopiowanie przykład z tego blog:

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

i kod dla @visitor dekoratora (w przypadku łącza idzie martwy):

# 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 

Powiązane blog (pierwsza już wydaje się być w dół): https://chris-lamb.co.uk/posts/visitor-pattern-in-python

EDIT:

obj.__qualname__ jest niedostępny dopiero w wersji Python 3.3, więc musimy użyć hack dla niższych wersjach: -

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 

Niestety powyższe rozwiązanie nie działa dla wersji Pythona poniżej 3,3, jako metody są nadal regularne funkcji, gdy przekazywane do dekorator. Możesz spróbować użyć zarówno dekoratora klas, jak i metody, zobacz Can a Python decorator of an instance method access the class?.