2013-10-22 7 views
5

Ist es möglich, Code aus importiertem Modul auf Modul anzuwenden, die es importieren? Zum Beispiel habe ich Modul Debug wo einige Dekorateur für das Debuggen definiert, zum Beispiel:Python Introspektion

def debug_func(f): 
    def wrapper(*func_args, **func_kwargs): 
     print(f(*func_args, **func_kwargs)) 
    return wrapper 

Was ist die Idee: Es wäre wenn ist nützlich sein, ich kann nur

import Debug 

und alle Funktionen von aktuellen Modul wird mit Dekorateur eingewickelt. Ist es möglich?

+1

Sie müßten nach dem Import eine Funktion in 'Debug' aufrufen; 'Debug 'kann wahrscheinlich nicht über das importierende Modul reflektieren, während es selbst importiert wird.IMHO, du bist besser dran '' von Debug importieren debug_func' und dann mit dem '@ debug_func' Dekorator auf die Funktionen, die es brauchen. Es wäre nicht zu schwer, eine Regexp zu schreiben, die alle Instanzen von '@ debug_func' in einer Datei kommentieren oder auskommentieren könnte. –

+1

Ich denke, du könntest eine 'decorate_all' Funktion schreiben, die eine Funktion als Parameter nimmt, alle' callable' Einträge in 'gobals()' betrachtet und sie oder etwas ähnliches verziert. Rufen Sie dies nach dem Import auf. –

Antwort

3

Innerhalb Debug.py:

import functools 
from types import FunctionType 

def wrap_functions(module_dict): 
    for k, f in module_dict.items(): 
     if not isinstance(f, FunctionType): 
      continue 
     def get_wrapper(f): 
      def wrapper(*func_args, **func_kwargs): 
       print(f(*func_args, **func_kwargs)) 
      return functools.wraps(f)(wrapper) 
     module_dict[k] = get_wrapper(f) 

Am unten des Moduls Sie debuggen wollen, sind:

import Debug 
Debug.wrap_functions(globals()) 

Dank (+1) an alle Kommentatoren, die Vorschläge zur Verfügung gestellt.

+0

Sie haben es rückwärts. Er möchte 'Debug importieren ', um die Funktionen des importierenden Moduls zu umbrechen, nicht die Funktionen von Debug. –

+1

Anstatt den Dekorator in die Funktion zu kopieren, übergeben Sie den/die Dekorator (en) nicht als weiteren Parameter? Verwenden Sie besser 'Debug.wrap_functions (globals())', sonst wird 'wrap_function' sich selbst schmücken. Abgesehen davon, +1 –

+1

Ich las Ihre ursprüngliche Antwort, ging dann weg, um etwas zu überprüfen und kam zurück zu finden, was ich geplant hatte zu schreiben :). –

0

Ich denke, die pythonic Art und Weise tun Sie Ihre Debug rufen Sie das debuggt Modul zu haben wäre, wie die Standard-Tools (pdb, unittest, ...) mit einem Aufruf wie:

$ python -m Debug mymodule.py 

Mit Ihrer Debuggen Importieren/Ausführen des Moduls mit beliebigen Dekoratoren. Anderenfalls (Importieren Debug) wird die Reihenfolge, in der die Module ausgewertet werden, falsch, da Sie versuchen, Ihr Modul Debug davon abhängig zu machen, dass das Modul es importiert, was bestenfalls knifflig ist.

Neben Ihre Funktionen explizit von vorbei (via globals(), eine Liste von Funktionen ...), um einige Debug.mark_as_debug als Jim Garrison vorgeschlagen, ich glaube, es würde mehr Sinn machen, Ihren Code zu organisieren, so dass Sie Ihre Debug anrufen können Ihre Module statt umgekehrt.

+0

Danke, aber ich schrieb Debug als Beispiel, primäres Problem - was ist der beste Weg, um Code aus dem importierten Modul auf Modul, die es importieren anzuwenden. – Dmitriy

+0

Ich denke, die Antwort auf diese Frage ist: Sie können nicht. Kindall erklärt es viel besser als ich, aber das Prinzip von Modulen geht dagegen (obwohl Sie Hooks hinzufügen können, um vom importierenden Modul aufgerufen zu werden, wie er und Jim Garrison zeigten). Ich glaube nicht, dass es einen (richtigen) Weg gibt, ein Modul seinen Caller zu kennen und ohne Callback zu modifizieren. – val

+0

Nun, technisch gesehen könnte man es mit einem Import-Hook machen, aber das scheint * sehr * dreckig zu sein. – kindall

3

Wie würde Debug wissen, aus welchem ​​Modul es importiert wird? Antwort: Es kann nicht. Wie kann Debug mehr als einmal ausgeführt werden, wenn es in mehr als ein Modul importiert wird? Antwort: Es würde nicht; Module werden nur einmal ausgeführt und dann zwischengespeichert. Was Sie also tun möchten, kann nicht ganz so einfach gemacht werden, wie Sie möchten.

Sie könnten dies jedoch tun, indem Sie nach dem Importieren eine Funktion in Ihrem debug Modul aufrufen. Sie können __name__ vom aufrufenden Modul übergeben, um seinen Namen anzugeben, nach dem es möglich ist, einen Verweis auf das Modul selbst und dann die darin definierten Variablen der obersten Ebene zu erhalten, von denen einige Funktionen sein können. Diese können dann dekoriert werden.

# debug.py 
import types, sys, functools 

# decorator to be applied to all top-level functions in a module 
def debug(fn): 
    @functools.wraps(fn) 
    def wrapper(*args, **kwargs): 
     print "calling", fn.__name__, "with args", *args, **kwargs 
     result = fn(*args, **kwargs) 
     print "returning from", fn.__name__, "with return value", result 
     return result 

# decorate all top-level functions in named module with a given decorator 
# (by default it is the above decorator but it could be a different one) 
# This makes these functions behave as though they had been written with 
# @debug above them. 
def set_debug(modname, debug=debug): 
    module = sys.modules[modname] 
    for name in dir(module): 
     if not name.startswith("_"): 
      thing = getattr(module, name) 
      if isinstance(thing, types.FunctionType): 
       setattr(module, name, debug(thing)) 

nun in dem rufenden Modul:

# main.py 
import debug 

def main(): 
    print "in main module" 

debug.set_debug(__name__) # install debugging decorator 

main() 

Jim Garrison Ansatz den Namespace explizit der Weitergabe (statt dem Modulnamen) ist auch gut und tatsächlich vereinfacht die Dinge ein wenig; Sie könnten damit andere Dinge als Module dekorieren. Ich habe meine kaputt gemacht, so dass du einen anderen Dekorateur einreichen kannst, wenn du willst.

Verwandte Themen