2012-11-01 16 views
27

Przepraszamy, jeśli to pytanie zostało już zgłoszone. To, co muszę zrobić, jest bardzo proste w koncepcji, ale niestety nie byłem w stanie znaleźć odpowiedzi na to online.Tworzenie dynamicznych funkcji Pythona o niestandardowych nazwach

Potrzebuję tworzyć dynamiczne funkcje w Pythonie (Python2.7) z niestandardowymi nazwami w czasie wykonywania. Ciało każdej funkcji również musi być skonstruowane w czasie wykonywania, ale jest (prawie) takie samo dla wszystkich funkcji.

Zacznę od listy nazwisk.

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

Należy zauważyć, że lista func_name może posiadać listę dowolnych nazwach, więc nazwy po prostu nie być func1, func2, func3, ....

Chcę być wynikiem:

def func1(*args): 
     ... 

    def func2(*args): 
     ... 

    def func3(*args): 
     ... 

Muszę to zrobić, ponieważ każda nazwa funkcji odpowiada przypadkowi testowemu, który jest następnie wywoływany ze świata zewnętrznego.

aktualizacja: Brak danych wprowadzanych przez użytkownika. Wiążę dwa końce znacznie większego modułu. Jeden koniec określa, jakie są przypadki testowe, i między innymi zapełnia listę nazw przypadków testowych. Drugim końcem są same funkcje, które muszą mieć odwzorowanie 1: 1 z nazwą przypadku testowego. Tak więc mam nazwy przypadków testowych, wiem, co chcę zrobić z każdym przypadkiem testowym, po prostu muszę utworzyć funkcje, które mają nazwę przypadków testowych. Ponieważ nazwy przypadków testowych są określane w środowisku wykonawczym, tworzenie funkcji na podstawie tych przypadków testowych musi również odbywać się w środowisku wykonawczym.

aktualizacja: Mogę również zawijać te niestandardowe funkcje nazwane w klasie, jeśli to ułatwiłoby pracę.

Mogę zakodować zawartość funkcji (ponieważ są prawie takie same) w ciągu znaków lub mogę ją oprzeć na wcześniej zdefiniowanej klasie bazowej. Wystarczy wiedzieć, jak wypełnić funkcje tą zawartością.

Na przykład:

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

Dzięki z góry,

Mahdi

Odpowiedz

1

Możesz użyć eval; zbudujesz łańcuch zawierający definicję Pythona dla każdej funkcji (tj. ciąg wielowierszowy zaczynający się od def func1 ....), a następnie uzyskasz eval.

Ale generowałbym unikalną nazwę dla każdej takiej funkcji (np. genfun345). Nie używaj niezatwierdzonych danych wejściowych dla takich nazw. Ponieważ jeśli nazwa jest taka sama, jak w przypadku znanej nazwy w Pythonie, przechodzi się do trudnej do debugowania katastrofy.

Czy wierzysz w dane wejściowe, z których tworzone są te funkcje? Czy interesuje Cię złośliwe oprogramowanie lub nadużycie?

Przeczytaj o hygenic macros na wikipedia.

+0

Nie ma wejście użytkownika. Wiążę dwa końce znacznie większego modułu. Jeden koniec określa, jakie są przypadki testowe, i między innymi zapełnia listę nazw przypadków testowych. Drugim końcem są same funkcje, które muszą mieć odwzorowanie 1: 1 z nazwą przypadku testowego. Tak więc mam nazwy przypadków testowych, wiem, co chcę zrobić z każdym przypadkiem testowym, po prostu muszę utworzyć funkcje, które mają nazwę przypadków testowych. Ponieważ nazwy przypadków testowych są określane w środowisku wykonawczym, tworzenie funkcji na podstawie tych przypadków testowych musi również odbywać się w środowisku wykonawczym. – mahdiolfat

33

Do tego, co opisujesz, nie sądzę, że musisz zejść w eval lub makra - tworzenie instancji funkcji przez zamknięcie powinno działać dobrze.Przykład:

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 

Jednakże, prawdopodobnie będziesz chciał dodać te funkcje przez nazwę w pewnym zakresie, dzięki czemu można uzyskać do nich po imieniu.

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

Prosty i działa. –

6

Prawdopodobnie jest to swego rodzaju introspekcji robić tego typu rzeczy, ale nie sądzę, że to będzie pythonic podejście do problemu.

Myślę, że powinieneś skorzystać z natury funkcji w Pythonie jako obywatele pierwszego poziomu. Użyj zamknięć, jak wskazał Shane Holloway, aby dostosować zawartość funkcji, jak chcesz. Następnie do dynamicznego powiązania nazw użyj słownika, którego kluczami są dynamicznie zdefiniowane nazwy, a wartościami będą same funkcje.

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) 

Mam nadzieję, że to ma sens w twoim przypadku użycia.

1

Jeśli mam zrozumienie wymagań poprawnie, to brzmi jak chcesz po prostu dynamicznie przydzielać dotychczasowych funkcji nowe lub alternatywne nazwy - w tym przypadku coś wzdłuż następujących linii powinien wykonać zadanie:

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

Dziękuję za odpowiedź. Ale tak nie jest. Nie są to istniejące funkcje, a ponadto nieznana jest liczba funkcji, które mają być tworzone dynamicznie (znane tylko w środowisku wykonawczym). – mahdiolfat

+0

Jeśli możesz "zakodować zawartość funkcji", możesz równie dobrze poprzedzić tę treść 'def xxx (yyy):' w pliku .py i sprawić, że będzie ona istnieć - jak myślisz " ponownie zyskujesz, umieszczając go w sznurku i dynamicznie tworząc z niego funkcję? – martineau

+0

Myślę, że źle zrozumiałeś to, co próbuję tutaj zrobić i tak naprawdę nie odpowiedziałem na moje pytanie, ale wciąż mówiłem, żeby zrobił coś innego. Mimo to dziękuję. Już rozwiązałem mój problem. – mahdiolfat

10

Rozszerzając odpowiedź Shane'a, ponieważ właśnie znalazłem to pytanie, szukając rozwiązania podobnego problemu. Uważaj na zakres zmiennych. Możesz uniknąć problemów z zasięgiem, używając funkcji generatora do zdefiniowania zasięgu. Oto przykład, który definiuje metody w klasie:

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) 

W użyciu:

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> 
Powiązane problemy