2014-09-17 12 views
8

Hier ist eine vereinfachte Implementierung des Besuchermusters in C++. Ist es möglich, so etwas in Python zu implementieren?Besuchermuster in Python

Ich brauche es, weil ich Objekte aus C++ - Code an eine Funktion in Python übergeben werde. Meine Idee war, einen Besucher in Python zu implementieren, um den Typ des Objekts herauszufinden.

Meine C++ Code:

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

Antwort

12

Das Besuchermuster in Python implementiert werden kann, ich es verwenden, um eine saubere Schnittstelle zwischen meinem implementieren Daten- und Präsentationsschicht. Die Datenschicht kann die Reihenfolge der Daten bestimmen. und die Präsentationsschicht einfach druckt/formatiert:

In meinem Datenmodul ich habe:

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

class typeA(visited): 
    .... 

Alle meine Datenklassen erben von dieser Klasse besucht, und die besuchte Klasse stellt auch einige einfache Funktionen für die grundlegende Daten alle meine Objekte brauchen z Name, Parent, etc, und Methoden für die Verwaltung der Child-Liste - die durch die oben verwendete Methode children() ausgesetzt ist. Jede der Unterklassen baut ihre eigenen Daten auf, hat ihre eigenen Eigenschaften und vielleicht sogar ihre eigene Kindklasse - die zur Kinderliste hinzugefügt wird, die von der besuchten Superklasse verwaltet wird.

Mein Besucher Klasse ist wie folgt:

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

die _find_data_instance ist ein Code, der eine Instanz von einem meiner Dateninstanzen oder findet baut. In meinem Fall haben alle meine Datenklassen einen Konstruktor, der eine objectId zurückgibt und zurückgibt, und das Besucherobjekt weiß, welche Datenklasse zu verwenden ist.

+0

Vielen Dank für Ihre Hilfe. – bogdan

+0

Ich weiß nicht, welche Python-Version Sie verwenden, aber in Version 2.7.6 ist der Aufruf 'instance' nicht vorhanden. Sie sollten 'isinstance' verwenden – Matthias

+0

@Matthias - guter Fang - wäre glücklich gewesen für Sie, das als ein Bearbeitungsvorschlag zu setzen –

3

Sie könnte implementieren diese in Python, aber es gibt wirklich keine Notwendigkeit. Python ist eine dynamische, interpretierte Sprache, was bedeutet, dass Typinformationen zur Laufzeit leicht verfügbar sind.

So Ihr obiges Beispiel könnte so einfach sein wie

class C1(object): 
    pass 

class C2(object): 
    pass 

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

die Ausbeute wird:

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

Vielen Dank für Ihre Hilfe! Ich hätte deine Antwort akzeptiert, aber Tony war ein wenig detaillierter. – bogdan

8

Sie können Dekoratoren verwenden, um zu bekommen, was Sie wollen. Kopieren ein Beispiel aus diesem 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!" 

und den Code für die @visitor Dekorateur (im Falle geht der Link tot):

# 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 

Verwandte Blog (erste scheint bereits nach unten zu sein): https://chris-lamb.co.uk/posts/visitor-pattern-in-python

EDIT:

obj.__qualname__ ist nicht verfügbar bis Python 3.3, also müssen wir einen Hack für niedrigere Versionen verwenden: -

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 

Leider ist die obige Lösung nicht für Python-Versionen unter 3.3 funktioniert, wie Methoden noch reguläre Funktionen sind, wenn sie eine bestandene Dekorateur. Sie können versuchen, sowohl einen Klassen- als auch einen Methoden-Decorator zu verwenden, siehe Can a Python decorator of an instance method access the class?.

Verwandte Themen