Funkcja Eval próbuje wykonać i zinterpretować przekazany do niej ciąg (argument) jako kod Pythona. x = 1 print (eval ('x + 1')) Wyjście powyższego kodu będzie wynosić 2. Wadą takiego podejścia jest to, że użytkownik uzyskuje niezależność pisania kodu, co może prowadzić do spustoszenia. Chociaż można ograniczyć użytkowników z dostęp do wielu zmiennych i metod poprzez przekazanie globalnego i lokalnego parametru w funkcji eval.
ATIF IBAD KHAN
Odpowiedzi:
276
Funkcja eval pozwala programowi Python uruchamiać kod Pythona wewnątrz siebie.
haha, to był trywialny przykład, ale możesz pozwolić użytkownikowi wpisać dowolne polecenie i pozwolić na wykonanie go przez Python. Aby użytkownik mógł wpisać ciąg znaków w poleceniu, a następnie uruchomić kod w Pythonie. Na przykład: eval („__ import __ ('os'). Remove ('file')”).
BYS2
60
Będzie to wydawać się bezużyteczne, dopóki nie znajdziesz takiej potrzeby. Jest używany w witrynach takich jak codepad.org, aby umożliwić wykonywanie skryptów w środowisku testowym. eval()może być również używany do wykonywania wysoce dynamicznego kodu, ale przed użyciem go należy w pełni zdawać sobie sprawę z zagrożeń bezpieczeństwa i wydajności.
George Cummins
6
@GeorgeCummins, codepad.org nie używa evalani nie może robić tego, co robi eval.
Mike Graham
16
@GeorgeCummins: codepag.org uruchamia wszystko w piaskownicy: więzienie chroot z kontrolą ptrace na maszynie wirtualnej, aby zapobiec szkodliwemu kodowi. O wiele bardziej skomplikowane niż zwykła ewaluacja. Ponadto eval jest specyficzny dla Pythona. codepad obsługuje wiele języków.
FogleBird,
4
@GeorgeCummins, codepad działa bardzo złożony system do bezpiecznego uruchamiania dowolnych programów. eval, poza niebezpieczeństwem, nie może uruchamiać całych programów, jak robi to w programie codepad, ponieważ może ocenić tylko jedno wyrażenie.
Mike Graham
165
eval()interpretuje ciąg jako kod. Powodem, dla którego tak wiele osób ostrzegło cię przed użyciem tego, jest to, że użytkownik może użyć tego jako opcji uruchamiania kodu na komputerze. Jeśli masz eval(input())i oszaimportowałeś, osoba może wpisać, w input()os.system('rm -R *')którym skasują wszystkie twoje pliki z twojego katalogu domowego. (Zakładając, że masz system uniksowy). Korzystanie eval()jest dziurą w zabezpieczeniach. Jeśli chcesz przekonwertować ciągi znaków na inne formaty, spróbuj użyć rzeczy, które to robią, takich jak int().
Masz na myśli używając evalze input()jest dziura bezpieczeństwa. Nie umieszczaj input()w ewaluacji oświadczenia, a wszystko będzie dobrze.
Rohmer
19
@Rohmer, niebezpieczne dane mogą pochodzić z dowolnego miejsca: żądania sieciowe, pola wprowadzania formularzy, odczyty plików ... nie tylko z danych wejściowych konsoli. Nawet jeśli sam napiszesz pliki, mogą one nadal zawierać dane wejściowe pochodzące z niezaufanego źródła. Podobnie evaljest w wielu przypadkach kwestia bezpieczeństwa.
sanderd17
3
ponieważ inputzwykle pobiera dane z konsoli, użytkownik może po prostu wyjść z programu i wpisać rm -R *mimo wszystko ...
cz
63
Wiele dobrych odpowiedzi tutaj, ale żadna nie opisuje użycia eval()w kontekście jego globalsi localskwargs, tj. eval(expression, globals=None, locals=None)(Patrz evaltutaj dokumenty ).
Można ich użyć do ograniczenia funkcji dostępnych za pośrednictwem evalfunkcji. Na przykład, jeśli załadujesz świeżego interpretera Pythona, locals()i globals()będą takie same i będą wyglądać mniej więcej tak:
Z pewnością w builtinsmodule znajdują się funkcje , które mogą wyrządzić znaczne szkody w systemie. Możliwe jest jednak zablokowanie czegokolwiek i wszystkiego, czego nie chcemy, aby były dostępne. Weźmy przykład. Powiedzmy, że chcemy zbudować listę reprezentującą domenę dostępnych rdzeni w systemie. Dla mnie mam 8 rdzeni, więc chciałbym listę [1, 8].
>>>from os import cpu_count
>>>eval('[1, cpu_count()]')[1,8]
Podobnie wszystko __builtins__jest dostępne.
>>>eval('abs(-1)')1
Ok. Widzimy więc jedną funkcję, którą chcemy ujawnić, oraz przykład jednej (z wielu, które mogą być znacznie bardziej złożone) metody, której nie chcemy ujawniać. Więc zablokujmy wszystko.
Skutecznie zablokowaliśmy wszystkie __builtins__funkcje i jako taki wprowadziliśmy poziom ochrony do naszego systemu. W tym momencie możemy zacząć dodawać funkcje, które chcemy udostępnić.
Teraz mamy cpu_countdostępną funkcję, wciąż blokując wszystko, czego nie chcemy. Moim zdaniem jest to bardzo potężne i wyraźnie z zakresu innych odpowiedzi, a nie powszechne wdrożenie. Istnieje wiele zastosowań czegoś takiego i pod warunkiem, że jest obsługiwany poprawnie, osobiście uważam, że evalmożna go bezpiecznie wykorzystać w świetnej cenie.
NB
Kolejną fajną kwargsrzeczą jest to, że możesz zacząć używać skrótu do swojego kodu. Załóżmy, że używasz eval jako części potoku do wykonania importowanego tekstu. Tekst nie musi mieć dokładnego kodu, może być zgodny z formatem plików szablonów i nadal wykonywać dowolne czynności. Na przykład:
>>>from os import cpu_count
>>>eval('[1,cores]',{'__builtins__':None},{'cores': cpu_count()})[1,8]
W Pythonie 2.x input(...)jest równoważne zmianie nazwy eval(raw_input(...))w Pythonie 3.x , co, jak podejrzewam, prowadzi do zamieszania (prawdopodobnie przeglądałeś dokumentację w Pythonie 2.x). Dodatkowo działałby dobrze w Pythonie 3.x, ale podniósłby a w Pythonie 2.raw_inputinputinputeval(input(...))TypeError
W tym przypadku evalsłuży do wymuszenia ciągu zwracanego z inputwyrażenia i interpretowanego. Ogólnie uważa się to za złą praktykę.
Dlaczego powinienem wpisywać go między cudzysłowami? Wejście pobiera ciąg znaków i przekazuje go do eval, nie wykonując kodu, więc powinienem być w porządku, jeśli po prostu wpisałbym 1 + 1 ... ¿?
JC Rocamonde
Chodzi o to, że miksujesz P2.x i 3.x. W Pythonie 2 twój kod działa, ale nie ma sensu sprawdzać dwukrotnie. W Pythonie 3 tak nie jest i zwraca ciąg znaków.
JC Rocamonde,
6
eval()ocenia przekazany ciąg jako wyrażenie w języku Python i zwraca wynik. Na przykład eval("1 + 1")interpretuje i wykonuje wyrażenie "1 + 1"i zwraca wynik (2).
Jednym z powodów, dla których możesz się mylić, jest to, że cytowany kod zawiera pewien poziom pośredni. Wewnętrzne wywołanie funkcji (wejście) jest wykonywane jako pierwsze, więc użytkownik widzi monit „bla”. Wyobraźmy sobie, że odpowiadają „1 + 1” (cytaty dodane dla zachowania przejrzystości, nie wpisuj ich podczas uruchamiania programu), funkcja wejściowa zwraca ten ciąg, który jest następnie przekazywany do funkcji zewnętrznej (eval), która interpretuje ciąg i zwraca wynik (2).
eval(), jak sama nazwa wskazuje, ocenia przekazany argument.
raw_input()jest teraz input()w wersji Python 3.x. Najczęściej spotykanym przykładem użycia eval()jest użycie tej funkcji w celu zapewnienia funkcjonalności, która jest input()dostępna w wersji Pythona w wersji 2.x. raw_input zwrócił dane wprowadzone przez użytkownika jako ciąg, podczas gdy dane wejściowe oszacowały wartość wprowadzonych danych i zwróciły je.
eval(input("bla bla"))w ten sposób replikuje funkcjonalność input()w 2.x, tj. ocenę danych wprowadzonych przez użytkownika.
W skrócie: eval()ocenia przekazane mu argumenty, a zatem eval('1 + 1')zwrócił 2.
Inną opcją, jeśli chcesz ograniczyć łańcuch oceny do prostych literałów, jest użycie ast.literal_eval(). Kilka przykładów:
import ast
# print(ast.literal_eval('')) # SyntaxError: unexpected EOF while parsing# print(ast.literal_eval('a')) # ValueError: malformed node or string# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax# print(ast.literal_eval('1+1')) # 2: but only works due to a quirk in parser# print(ast.literal_eval('1*1')) # ValueError: malformed node or stringprint(ast.literal_eval("{'a':1}"))# {'a':1}
Bezpiecznie oceń węzeł wyrażenia lub ciąg znaków zawierający literał Pythona lub wyświetlacz kontenera. Podany ciąg znaków lub węzeł może składać się wyłącznie z następujących struktur literału Pythona: ciągów, bajtów, liczb, krotek, list, dykt, zestawów, boolanów i Brak.
Można to wykorzystać do bezpiecznej oceny ciągów zawierających wartości Pythona z niezaufanych źródeł bez konieczności samodzielnego analizowania wartości. To nie stanie ocenić dowolnie złożonych wyrażeń, na przykład z udziałem operatorów lub indeksowanie.
Jeśli chodzi o to, dlaczego jest tak ograniczony, z listy mailingowej :
Dopuszczanie wyrażeń operatora z literałami jest możliwe, ale o wiele bardziej skomplikowane niż bieżąca implementacja. Prosta implementacja nie jest bezpieczna: bez problemu można indukować praktycznie nieograniczone użycie procesora i pamięci (spróbuj „9 ** 9 ** 9” lub „[Brak] * 9 ** 9”).
Jeśli chodzi o użyteczność, funkcja ta jest przydatna do „odczytania” dosłownych wartości i pojemników, jak określono w repr (). Można to na przykład wykorzystać do serializacji w formacie, który jest podobny do JSON, ale bardziej wydajny.
ast.literal_evalnie obsługuje operatorów, w przeciwieństwie do twojego '1+1'przykładu. Niemniej jednak obsługuje listy, liczby, ciągi itp., A zatem jest dobrą alternatywą dla typowych evalprzypadków użycia.
Odpowiedzi:
Funkcja eval pozwala programowi Python uruchamiać kod Pythona wewnątrz siebie.
przykład eval (powłoka interaktywna):
źródło
eval()
może być również używany do wykonywania wysoce dynamicznego kodu, ale przed użyciem go należy w pełni zdawać sobie sprawę z zagrożeń bezpieczeństwa i wydajności.eval
ani nie może robić tego, co robieval
.eval
, poza niebezpieczeństwem, nie może uruchamiać całych programów, jak robi to w programie codepad, ponieważ może ocenić tylko jedno wyrażenie.eval()
interpretuje ciąg jako kod. Powodem, dla którego tak wiele osób ostrzegło cię przed użyciem tego, jest to, że użytkownik może użyć tego jako opcji uruchamiania kodu na komputerze. Jeśli maszeval(input())
ios
zaimportowałeś, osoba może wpisać, winput()
os.system('rm -R *')
którym skasują wszystkie twoje pliki z twojego katalogu domowego. (Zakładając, że masz system uniksowy). Korzystanieeval()
jest dziurą w zabezpieczeniach. Jeśli chcesz przekonwertować ciągi znaków na inne formaty, spróbuj użyć rzeczy, które to robią, takich jakint()
.źródło
eval
zeinput()
jest dziura bezpieczeństwa. Nie umieszczajinput()
w ewaluacji oświadczenia, a wszystko będzie dobrze.eval
jest w wielu przypadkach kwestia bezpieczeństwa.input
zwykle pobiera dane z konsoli, użytkownik może po prostu wyjść z programu i wpisaćrm -R *
mimo wszystko ...Wiele dobrych odpowiedzi tutaj, ale żadna nie opisuje użycia
eval()
w kontekście jegoglobals
ilocals
kwargs, tj.eval(expression, globals=None, locals=None)
(Patrzeval
tutaj dokumenty ).Można ich użyć do ograniczenia funkcji dostępnych za pośrednictwem
eval
funkcji. Na przykład, jeśli załadujesz świeżego interpretera Pythona,locals()
iglobals()
będą takie same i będą wyglądać mniej więcej tak:Z pewnością w
builtins
module znajdują się funkcje , które mogą wyrządzić znaczne szkody w systemie. Możliwe jest jednak zablokowanie czegokolwiek i wszystkiego, czego nie chcemy, aby były dostępne. Weźmy przykład. Powiedzmy, że chcemy zbudować listę reprezentującą domenę dostępnych rdzeni w systemie. Dla mnie mam 8 rdzeni, więc chciałbym listę[1, 8]
.Podobnie wszystko
__builtins__
jest dostępne.Ok. Widzimy więc jedną funkcję, którą chcemy ujawnić, oraz przykład jednej (z wielu, które mogą być znacznie bardziej złożone) metody, której nie chcemy ujawniać. Więc zablokujmy wszystko.
Skutecznie zablokowaliśmy wszystkie
__builtins__
funkcje i jako taki wprowadziliśmy poziom ochrony do naszego systemu. W tym momencie możemy zacząć dodawać funkcje, które chcemy udostępnić.Teraz mamy
cpu_count
dostępną funkcję, wciąż blokując wszystko, czego nie chcemy. Moim zdaniem jest to bardzo potężne i wyraźnie z zakresu innych odpowiedzi, a nie powszechne wdrożenie. Istnieje wiele zastosowań czegoś takiego i pod warunkiem, że jest obsługiwany poprawnie, osobiście uważam, żeeval
można go bezpiecznie wykorzystać w świetnej cenie.NB
Kolejną fajną
kwargs
rzeczą jest to, że możesz zacząć używać skrótu do swojego kodu. Załóżmy, że używasz eval jako części potoku do wykonania importowanego tekstu. Tekst nie musi mieć dokładnego kodu, może być zgodny z formatem plików szablonów i nadal wykonywać dowolne czynności. Na przykład:źródło
W Pythonie 2.x
input(...)
jest równoważne zmianie nazwyeval(raw_input(...))
w Pythonie 3.x , co, jak podejrzewam, prowadzi do zamieszania (prawdopodobnie przeglądałeś dokumentację w Pythonie 2.x). Dodatkowo działałby dobrze w Pythonie 3.x, ale podniósłby a w Pythonie 2.raw_input
input
input
eval(input(...))
TypeError
W tym przypadku
eval
służy do wymuszenia ciągu zwracanego zinput
wyrażenia i interpretowanego. Ogólnie uważa się to za złą praktykę.źródło
input
co oznacza to, coraw_input
zrobiono w wersji 2.x.Może wprowadzający w błąd przykład czytania linii i interpretowania jej.
Spróbuj
eval(input())
i wpisz"1+1"
- powinno to zostać wydrukowane2
. Eval ocenia wyrażenia.źródło
eval()
ocenia przekazany ciąg jako wyrażenie w języku Python i zwraca wynik. Na przykładeval("1 + 1")
interpretuje i wykonuje wyrażenie"1 + 1"
i zwraca wynik (2).Jednym z powodów, dla których możesz się mylić, jest to, że cytowany kod zawiera pewien poziom pośredni. Wewnętrzne wywołanie funkcji (wejście) jest wykonywane jako pierwsze, więc użytkownik widzi monit „bla”. Wyobraźmy sobie, że odpowiadają „1 + 1” (cytaty dodane dla zachowania przejrzystości, nie wpisuj ich podczas uruchamiania programu), funkcja wejściowa zwraca ten ciąg, który jest następnie przekazywany do funkcji zewnętrznej (eval), która interpretuje ciąg i zwraca wynik (2).
Przeczytaj więcej o eval tutaj .
źródło
eval()
, jak sama nazwa wskazuje, ocenia przekazany argument.raw_input()
jest terazinput()
w wersji Python 3.x. Najczęściej spotykanym przykładem użyciaeval()
jest użycie tej funkcji w celu zapewnienia funkcjonalności, która jestinput()
dostępna w wersji Pythona w wersji 2.x. raw_input zwrócił dane wprowadzone przez użytkownika jako ciąg, podczas gdy dane wejściowe oszacowały wartość wprowadzonych danych i zwróciły je.eval(input("bla bla"))
w ten sposób replikuje funkcjonalnośćinput()
w 2.x, tj. ocenę danych wprowadzonych przez użytkownika.W skrócie:
eval()
ocenia przekazane mu argumenty, a zatemeval('1 + 1')
zwrócił 2.źródło
Jedną z przydatnych aplikacji
eval()
jest ocena wyrażeń Pythona na podstawie ciągu znaków. Na przykład załaduj z reprezentacji ciągu słownika pliku:Przeczytaj jako zmienną i edytuj:
Wynik:
źródło
eval
?Spóźniłem się z odpowiedzią na to pytanie, ale wydaje się, że nikt nie udzielił jasnej odpowiedzi na to pytanie.
Jeśli użytkownik wprowadzi wartość liczbową,
input()
zwróci ciąg.Tak więc
eval()
oceni zwracaną wartość (lub wyrażenie), która jest łańcuchem i zwraca liczbę całkowitą / liczbę zmiennoprzecinkową.Oczywiście jest to zła praktyka.
int()
lubfloat()
powinien być użyty zamiasteval()
w tym przypadku.źródło
Inną opcją, jeśli chcesz ograniczyć łańcuch oceny do prostych literałów, jest użycie
ast.literal_eval()
. Kilka przykładów:Z dokumentów :
Jeśli chodzi o to, dlaczego jest tak ograniczony, z listy mailingowej :
źródło
ast.literal_eval
nie obsługuje operatorów, w przeciwieństwie do twojego'1+1'
przykładu. Niemniej jednak obsługuje listy, liczby, ciągi itp., A zatem jest dobrą alternatywą dla typowycheval
przypadków użycia.