2016-04-25 12 views
3

Ich baue SPA auf Django und ich habe eine große Funktion mit vielen if-Anweisung für die Überprüfung des Zustands meines Objekts Feld. Wie folgt:SingleVersion basierend auf Wert anstelle des Typs

if self.state == 'new': 
    do some logic 
if self.state == 'archive': 
    do some logic 

und so weiter. Ich lese schönes Buch "Fluent Python" jetzt, und ich erwähne etwa @singledispatch Dekorateur, es sieht so toll aus, aber es kann Funktion nur mit anderen Arten von Parametern wie str, int, etc.
Frage ist, ob es in Python oder Django Weg, Logik wie in meiner großen Funktion mit übersteuerten Funktion wie singledispatch zu trennen trennen?

Antwort

3

Es gibt, obwohl Sie es schreiben müssen. Eine Möglichkeit ist eine descriptor zu erstellen, die die Dispatching tut basierend auf instance.state oder beliebigen state_attr:

class StateDispatcher(object): 

    def __init__(self, state_attr='state'): 
     self.registry = {} 
     self._state_attr = state_attr 

    def __get__(self, instance, owner): 
     if instance is None: 
      return self 

     method = self.registry[getattr(instance, self._state_attr)] 
     return method.__get__(instance, owner) 

    def register(self, state): 
     def decorator(method): 
      self.registry[state] = method 
      return method 

     return decorator 

https://docs.python.org/3/howto/descriptor.html#functions-and-methods:

Methodenaufrufe Zur Unterstützung der Funktionen gehören die __get__() Verfahren zur Methoden während Attribut Zugriffs Bindung . Dies bedeutet, dass alle Funktionen Nicht-Datendeskriptoren sind, die gebundene oder ungebundene Methoden abhängig davon zurückgeben, ob sie von einem Objekt oder einer Klasse aufgerufen werden.

In Ihrer Stateful-Klasse können Sie dann einen Dispatcher erstellen und registrieren Methoden:

class StateMachine(object): 

    dispatcher = StateDispatcher() 
    state = None 

    @dispatcher.register('test') 
    def test(self): 
     print('Hello, World!', self.state) 

    @dispatcher.register('working') 
    def do_work(self): 
     print('Working hard, or hardly working?', self.state) 

ist es in Aktion Lassen Sie sehen:

>>> sm = StateMachine() 
>>> sm.state = 'test' 
>>> sm.dispatcher() 
Hello, World! test 
>>> sm.state = 'working' 
>>> sm.dispatcher() 
Working hard, or hardly working? working 
>>> sm.state = None 
>>> sm.dispatcher() 
Traceback (most recent call last): 
    ... 
    File "dispatcher.py", line 11, in __get__ 
    method = self.registry[getattr(instance, self._state_attr)] 
KeyError: None 

Hinweis, dass dies eine ziemlich böse Methode des Versands basierend auf dem Status, da für zukünftige Leser Ihres Codes der ganze Mechanismus schwer zu folgen sein wird.

Eine weitere Methode, Textstatus zu senden, besteht darin, den Status in Ihren Methodennamen zu codieren und auf dieser Grundlage in einer Dispatching-Funktion die richtige Methode auszuwählen. Viele Python-Klassen verwenden dieses Muster (ast.NodeVisitor zum Beispiel):

class StateMachine(object): 

    def dispatch(self, *args, **kwgs): 
     getattr(self, 'do_{}'.format(self.state))(*args, **kwgs) 

    def do_new(self): 
     print('new') 

    def do_archive(self): 
     print('archive') 


sm = StateMachine() 
sm.state = 'new' 
sm.dispatch() 
sm.state = 'archive' 
sm.dispatch() 
+1

Vielen viel für Antwort intresting. Ich muss wirklich diese "descriptor" Magie lernen –

Verwandte Themen