2010-11-11 14 views
8

Tak więc zrozumiałem, co robią exec i eval, a także compile. Ale dlaczego miałbym ich używać? Nie mam pewności co do scenariusza użycia.Użycie exec i eval w Pythonie

Czy ktoś może podać mi kilka przykładów, aby móc lepiej docenić koncepcję. Bo w porządku, wiem, że to wszystko jest teoria.

+3

Fakt: rzeczy takie jak 'eval' są bardzo rzadko ważnym wyborem i tylko wtedy, gdy ciąg podawany do nich jest znany jako bezpieczny. – delnan

+4

Spróbuj wyszukać je w plikach kodu źródłowego Python w bibliotece standardowej Python. To zawsze jest ciekawe miejsce do rozpoczęcia, jeśli chcesz, aby podstawowe funkcje Pythona były dobrze wykorzystane. –

+0

'exec' i' eval' mogą być całkiem przydatne w [codegolfing] (https://codegolf.stackexchange.com/). – Wrzlprmft

Odpowiedz

5

Podam przykład, w którym użyłem eval i gdzie uważam, że był to najlepszy wybór.

Pisałem proste narzędzie do testowania oprogramowania ... coś do sprawdzenia, czy ćwiczenia studentów były zgodne z wymaganiami zadania.Celem było udostępnienie prostego pliku konfiguracyjnego służącego jako specyfikacja testu (aby obejść problem "kurczaków i jaj" używania języka programowania do opisywania/dokumentowania/implementowania przypadków testowych dla elementarnych przydziałów programowania) .

Oparłem swoją uprząż na ConfigParser w standardowych bibliotekach. Jednak chciałam zdolność do reprezentowania dowolne ciągi Python (w tym interpolacji \ n \ t, a zwłaszcza każdy interpolowana hex zakodowane znaki ASCII wartości odczytu z niego.

Moje rozwiązanie było try wokół parsed_string=eval('''%s''' % cfg_read_item) następnie a try potrójnej wersji podwójnej ("" "% s" "") tego samego.

Jest to przypadek, w którym alternatywą byłoby napisanie (lub znalezienie wcześniej napisanego) parsera językowego w języku Python Ryzyko jest minimalne (nie obawiam się, że kod przesłany przez studenta oszuka mój parser, złamie jego więzienie, usunie wszystkie moje pliki, wyśle ​​numery kart kredytowych do Rumunii itd.) *

* (Częściowo dlatego, że testowałem je pod Linuksem z niezaufanego konta bez głowy).

Jak już powiedzieli inni, istnieją inne przypadki użycia, w których budujesz kod z szablonu na podstawie danych wejściowych i potrzebujesz wykonać ten kod (programowanie meta). Zawsze powinieneś być w stanie wykonać te zadania w inny sposób. Jednak zawsze, gdy ta alternatywa wymaga wysiłku związanego z kodowaniem, który zbliża się do napisania ogólnego parsera/kompilatora/języka tłumaczącego dla języka polskiego, lepszym podejściem może być eval.

0

Po prostu pytasz o przykład? Możesz napisać prostą aplikację, która czyta ze standardowego wejścia i pozwala użytkownikowi wprowadzać różne wyrażenia, takie jak (4*2)/8 - 1. W innych językach (Java, C++, itd.), To byłoby prawie niemożliwe do oceny, ale w Pythonie jest proste, wystarczy:

eval((4*2)/8 - 1) 

W takiej sytuacji, jeśli nie jesteś ostrożny, korzystając z tych rzeczy może być bardzo niebezpieczne, ponieważ (zasadniczo) pozwalają użytkownikowi na ogromną ilość dostępu.

+1

Nie "bliski niemożliwemu do oceny" --- sam Python jest napisany głównie w języku C, a Python potrafi ocenić takie wyrażenia. Lepiej powiedzieć, że ocena wyrażeń pociągnie za sobą tyle samo pracy, co napisanie parsera języka programowania i kompilatora lub tłumacza. –

+1

@Jim Dennis. Uzgodniono, że nie jest "prawie niemożliwe". Jest to możliwe, biorąc pod uwagę kilka godzin, a może nawet mniej. Ale to jest ból. – nosirrahcd

0

Służy do meta-programowania (gdy program sam się pisze). Na przykład masz zwierzęta różnych gatunków, które opisują różne klasy: Lew, Tygrys, Koń, Osioł. I chcesz symulować krzyżowanie między nimi, na przykład, pomiędzy Lwem a Tygrysem. Podczas pisania programu, nie można ustalić, w jaki sposób użytkownik będzie przejechać przez zwierzęta, ale można tworzyć nowe klasy zwierząt w locie:

new_class_name = boy.class.to_str() + girl.class.to_str() 
eval("class " + new_class_name + " extends " + boy.class.to_str() + ", " + girl.class.to_str()) 

P. S. Niestety, zapomniałem Python niektórych. Tak więc istnieje pseudo-kod.

+4

Nie, to nie jest prawidłowe użycie 'eval' - powinieneś użyć' type'. – katrielalex

1

Nie musisz , nie potrzebujesz, aby z nich korzystać, i moim zdaniem powinieneś ich unikać.

Są one użyteczne tylko w przypadkach, w których generowany jest sam kod, który ostatecznie najprawdopodobniej zostanie uznany za niewłaściwą praktykę.

Jeśli rozważasz użycie eval() do takich rzeczy, jak wyrażenia matematyczne, lepiej oczyścić dane wejściowe przed ich oceną. Nigdy nie wiesz, jakiego rodzaju "tekst" wysyła użytkownik, który może zepsuć samą aplikację.

+5

Posiadanie "meta-programowania" równego "złej praktyce" jest nieco surowe, IMHO. Meta-programowanie, czasami bardziej złożone i bardziej podatne na błędy, może przynieść lepsze (tj. Szybsze lub łatwiejsze do utrzymania w działaniu) kodowanie, gdy jest właściwie używane. – Kos

+1

Meta-programowanie nie jest złe. Może być bardzo beautful. –

+0

Każde narzędzie i metoda ma swoją domenę zastosowania.Ale masz rację, domena zastosowania meta-programowania jest bardzo wąska. –

4

Standardowa biblioteka ma pouczający przykład użycia exec. collections.namedtuple używa go do dynamicznego budowania klasy.

template = '''class %(typename)s(tuple): 
    '%(typename)s(%(argtxt)s)' \n 
    __slots__ =() \n 
    _fields = %(field_names)r \n 
    def __new__(_cls, %(argtxt)s): 
     'Create new instance of %(typename)s(%(argtxt)s)' 
     return _tuple.__new__(_cls, (%(argtxt)s)) \n 
    ...''' 

    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, 
        OrderedDict=OrderedDict, _property=property, _tuple=tuple) 
    try: 
     exec template in namespace 
    except SyntaxError, e: 
     raise SyntaxError(e.message + ':\n' + template) 
+2

Mówiąc o szalonym programowaniu ... – Unode

+0

Prawdopodobnie zrobiłbym to z metaclassem –

+0

używając funkcji wyższego rzędu –

3

ast wykorzystuje compile wygenerować drzewo składniowe z kodu źródłowego Python. Są one używane przez moduły takie jak pyflakes do analizowania i sprawdzania poprawności Pythona.

def parse(expr, filename='<unknown>', mode='exec'): 
    """ 
    Parse an expression into an AST node. 
    Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST). 
    """ 
    return compile(expr, filename, mode, PyCF_ONLY_AST) 
0

Oto ważny przypadek użycia. W pythonie wkleja oprogramowanie pośredniczące (do programowania sieci), gdy wyjątek zostanie podniesiony, tworzy wiersz poleceń w przeglądarce. To działa przy użyciu takich metod. Ponadto w Blenderze istnieje opcja animowania wartości za pomocą wyrażeń Pythona, a to działa przy użyciu eval.

1

Myślę, że mam ważne zastosowanie. Używam Python 3.2.1 w Blenderze 2.6.4, aby zmodyfikować zestaw punktów o współrzędnych x, y (w płaszczyźnie z).

Celem jest dodanie koncentrycznych pierścieni z nowymi punktami wokół każdego istniejącego punktu, z pierścieniami zachowującymi się jak zmarszczki (np. Kiedy upuszczasz kamień w stawie). Chwytanie polega na tym, że chcę, aby zmarszczki konstruktywnie/niszcząco ingerowały w siebie, więc najpierw przechodzę i konstruuję "równanie tętnienia" skupione w każdym punkcie i sumuję wszystkie równania marszczyć razem w jednym gigantycznym równaniu matematycznym, które Następnie dodam oryginalne punkty, aby wygenerować poprawną wartość z, do której każdy będzie przypisany.

Mój plan to dołączenie każdego dodatkowego wyrażenia w równaniu do poprzedniego jako ciągu, a następnie użycie eval() do obliczenia wartości z dla nowego zestawu punktów.