2012-11-01 18 views
27

Entschuldigung, wenn diese Frage bereits gestellt und beantwortet wurde. Was ich tun muss, ist sehr einfach im Konzept, aber leider konnte ich online keine Antwort dafür finden.Python dynamische Funktionserstellung mit benutzerdefinierten Namen

Ich muss dynamische Funktionen in Python (Python2.7) mit benutzerdefinierten Namen zur Laufzeit erstellen. Der Rumpf jeder Funktion muss auch zur Laufzeit aufgebaut werden, ist aber für alle Funktionen (fast) identisch.

Ich fange mit einer Liste von Namen an.

func_names = ["func1", "func2", "func3"] 

Beachten Sie, dass die func_name Liste eine Liste von beliebigen Namen halten kann, so die Namen einfach nicht func1, func2, func3 sein, ....

Ich möchte das Ergebnis sein:

def func1(*args): 
     ... 

    def func2(*args): 
     ... 

    def func3(*args): 
     ... 

Der Grund, warum ich dies tun muss, ist, dass jeder Funktionsname einem Testfall entspricht, der dann von der Außenwelt aufgerufen wird.

Aktualisierung: Es gibt keine Benutzereingabe. Ich bin zwei Enden eines viel größeren Moduls gebunden. Ein Ende bestimmt, was die Testfälle sind und füllt unter anderem eine Liste der Namen der Testfälle auf. Das andere Ende sind die Funktionen selbst, die 1: 1 mit dem Namen des Testfalls mappen müssen. Also habe ich den Namen der Testfälle, ich weiß, was ich mit jedem Testfall machen will, ich muss nur die Funktionen erstellen, die den Namen der Testfälle haben. Da der Name der Testfälle zur Laufzeit ermittelt wird, muss die auf diesen Testfällen basierende Funktionserstellung auch zur Laufzeit erfolgen.

update: Ich kann diese benutzerdefinierten benannten Funktionen auch in eine Klasse umbrechen, wenn das die Dinge einfacher machen würde.

Ich kann den Inhalt der Funktionen (da sie fast identisch sind) in einer Zeichenfolge fest codieren, oder ich kann sie von einer zuvor definierten Basisklasse ableiten. Ich muss nur wissen, wie man die Funktionen mit diesem Inhalt füllt.

Zum Beispiel:

func_content = """ 
        for arg in args: 
         print arg 
        """ 

Vielen Dank im Voraus,

Mahdi

Antwort

1

Sie wollen eval verwenden können; Sie werden die Zeichenfolge erstellen, die die Python-Definition jeder Funktion enthält (d. h. eine mehrzeilige Zeichenfolge, die mit def func1 .... beginnt) und Sie werden dann eval es.

Aber ich würde einen eindeutigen Namen für jede solche Funktion (z. B. genfun345) generieren. Verwenden Sie keine ungeprüften Benutzereingaben für solche Namen. Denn wenn der Name mit einem bekannten Namen in Python übereinstimmt, geht es in ein schwer zu behebendes Desaster.

Vertrauen Sie den Eingängen, von denen diese Funktionen stammen? Interessieren Sie sich für Malware oder Missbrauch?

Lesen Sie über hygenic macros auf Wikipedia.

+0

Es gibt keine Benutzereingaben. Ich bin zwei Enden eines viel größeren Moduls gebunden. Ein Ende bestimmt, was die Testfälle sind und füllt unter anderem eine Liste der Namen der Testfälle auf. Das andere Ende sind die Funktionen selbst, die 1: 1 mit dem Namen des Testfalls mappen müssen. Also habe ich den Namen der Testfälle, ich weiß, was ich mit jedem Testfall machen will, ich muss nur die Funktionen erstellen, die den Namen der Testfälle haben. Da der Name der Testfälle zur Laufzeit ermittelt wird, muss die auf diesen Testfällen basierende Funktionserstellung auch zur Laufzeit erfolgen. – mahdiolfat

33

Für was Sie beschreiben, ich glaube nicht, dass Sie in Eval oder Makros absteigen müssen - Erstellen von Funktionsinstanzen durch Schließung sollte gut funktionieren.Beispiel:

def bindFunction1(name): 
    def func1(*args): 
     for arg in args: 
      print arg 
     return 42 # ... 
    func1.__name__ = name 
    return func1 

def bindFunction2(name): 
    def func2(*args): 
     for arg in args: 
      print arg 
     return 2142 # ... 
    func2.__name__ = name 
    return func2 

Sie werden jedoch wahrscheinlich diese Funktionen nach dem Namen zu einem Bereich hinzufügen, so dass Sie über den Namen darauf zugreifen können.

>>> print bindFunction1('neat') 
<function neat at 0x00000000629099E8> 
>>> print bindFunction2('keen') 
<function keen at 0x0000000072C93DD8> 
+0

Einfach und funktioniert. –

6

Es gibt wohl eine Art Selbstbeobachtung diese Art der Sache zu tun, aber ich glaube nicht, dass die pythonic Herangehensweise an das Problem sei.

Ich denke, Sie sollten die Natur der Funktionen in Python als Bürger der ersten Ebene nutzen. Verwenden Sie Verschlüsse, wie Shane Holloway gezeigt hat, um den Funktionsinhalt nach Belieben anzupassen. Verwenden Sie dann für die dynamische Namensbindung ein Wörterbuch, dessen Schlüssel die dynamisch definierten Namen sind, und die Werte die Funktionen selbst sind.

def function_builder(args): 
    def function(more_args): 
     #do stuff based on the values of args 
    return function 

my_dynamic_functions = {} 
my_dynamic_functions[dynamic_name] = function_builder(some_dynamic_args) 

#then use it somewhere else 
my_dynamic_functions[dynamic_name](the_args) 

Ich hoffe, es macht Sinn für Ihren Anwendungsfall.

1

Wenn ich Ihre Anforderungen richtig zu verstehen, es klingt wie Sie nur dynamisch wollen neue oder alternative Namen bestehenden Funktionen zuweisen - in diesem Fall etwas in den folgenden Zeilen sollten den Job erledigen:

import sys 

testcases = [] 
def testcase(f): 
    """ testcase function decorator """ 
    testcases.append(f) 
    return f 

@testcase 
def testcase0(*args): 
    print 'testcase0 called, args:', args 

@testcase 
def testcase1(*args): 
    print 'testcase1 called, args:', args 

@testcase 
def testcase2(*args): 
    print 'testcase2 called, args:', args 

def assign_function_names(func_names, namespace=None): 
    if namespace is None: 
     namespace = sys._getframe(1).f_globals # default to caller's globals 
    for name, func in zip(func_names, testcases): 
     func.__name__ = name # optional 
     namespace[name] = func 

assign_function_names(["funcA", "funcB", "funcC"]) 

funcA(1, 2, 3) 
funcB(4, 5) 
funcC(42) 
+0

Danke für Ihre Antwort. Aber das ist nicht der Fall. Sie sind keine existierenden Funktionen und außerdem ist die Anzahl der Funktionen, die dynamisch erzeugt werden sollen, ebenfalls unbekannt (nur zur Laufzeit bekannt). – mahdiolfat

+0

Wenn Sie den Inhalt der Funktionen "fest codieren" können Sie auch diesen Inhalt mit einem 'def xxx (yyy):' in einer .py-Datei voranstellen und eine existierende Funktion machen - was denken Sie? Re gewinnen, indem Sie es in eine Zeichenfolge einfügen und daraus dynamisch eine Funktion erstellen? – martineau

+0

Ich denke, du hast missverstanden, was ich hier versuche, und habe meine Frage nicht wirklich beantwortet, aber erzähle weiter, etwas anderes zu tun. Danke trotzdem. Ich habe mein Problem bereits gelöst. – mahdiolfat

10

Erweitere Shanes Antwort, da ich gerade diese Frage bei der Suche nach einer Lösung für ein ähnliches Problem gefunden habe. Achten Sie auf den Umfang der Variablen. Sie können Probleme mit dem Oszilloskop vermeiden, indem Sie den Bereich mithilfe einer Generatorfunktion definieren. Hier ist ein Beispiel, das Verfahren auf einer Klasse definiert:

class A(object): 
    pass 

def make_method(name): 
    def _method(self): 
     print("method {0} in {1}".format(name, self)) 
    return _method 

for name in ('one', 'two', 'three'): 
    _method = make_method(name) 
    setattr(A, name, _method) 

Im Einsatz:

In [4]: o = A() 

In [5]: o.one() 
method one in <__main__.A object at 0x1c0ac90> 

In [6]: o1 = A() 

In [7]: o1.one() 
method one in <__main__.A object at 0x1c0ad10> 

In [8]: o.two() 
method two in <__main__.A object at 0x1c0ac90> 

In [9]: o1.two() 
method two in <__main__.A object at 0x1c0ad10> 
Verwandte Themen