Szczerze mówiąc, w przeciwieństwie do drugiego pytania, to pytanie nie jest duplikatem. Inni zadali o wiele więcej podstawowych pytań niż to.
DNS
8
Prawidłowa odpowiedź to prawie zawsze „nie!”.
bobince
23
@S. Lott: Nie czytałeś ostatnio FAQ? „Można również zadawać własne pytania dotyczące programowania i odpowiadać na nie, ale udawać, że jesteś w Jeopardy: sformułuj je w formie pytania”. To nie jest złe pytanie. +1
Devin Jeanpierre
49
@ S.Lott: Nie. Nie musisz. Jeśli pytania nie ma jeszcze na stronie, oznacza to, że jest to uczciwa gra (zgodnie z FAQ, jak już wspomniano). Odpowiedz tylko na każde pytanie, tak jakby PO potrzebuje pomocy. Być może nie, ale prawdopodobnie zrobi to następny facet, który przeczyta ich pytanie. Tylko moje 2 centy.
Bill the Lizard
1
Do wszystkich, którzy mówią, żeby tego nie robić: mam przypadek, w którym absolutnie muszę. Obejmuje przetwarzanie rozproszone.
>>> mycode ='print "hello world"'>>>exec(mycode)Hello world
Jeśli potrzebujesz wartości wyrażenia, użyj eval(string):
>>> x = eval("2+2")>>> x
4
Jednak pierwszym krokiem powinno być zadanie sobie pytania, czy naprawdę potrzebujesz. Wykonywanie kodu powinno zasadniczo być ostatecznością: jest powolne, brzydkie i niebezpieczne, jeśli może zawierać kod wprowadzony przez użytkownika. Zawsze powinieneś najpierw spojrzeć na alternatywy, takie jak funkcje wyższego rzędu, aby sprawdzić, czy mogą one lepiej zaspokoić twoje potrzeby.
ale co z zakresem kodu wykonywanego przez „exec”? czy jest zagnieżdżony?
jondinham,
21
Częstym przypadkiem, gdy ktoś chce użyć „exec”, jest coś w rodzaju if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42itp., Które może następnie zapisać jako exec ("x.%s = 42" % s). W tym typowym przypadku (gdy potrzebujesz tylko dostępu do atrybutu obiektu przechowywanego w ciągu), istnieje znacznie szybsza, czystsza i bezpieczniejsza funkcja getattr: po prostu pisz, getattr(x, s) = 42aby oznaczać to samo.
ShreevatsaR
5
W jaki sposób exec działa wolniej niż interpreter Pythona?
Cris Stringfellow
6
@ShreevatsaR nie masz na myśli setattr(x, s, 42)? Próbowałem getattr(x, 2) = 42i nie udało sięcan't assign to function call: <string>, line 1
Tanner Semerad,
6
@Tanner: Hmm. Tak, rzeczywiście setattr(x, s, 42)jest poprawna składnia. Zaskoczony, że tak długo zajęło wykrycie tego błędu. W każdym razie chodzi o to, że getattri setattrsą alternatywą dla execkiedy chcesz to dostać dowolny element, spojrzał w górę przez struny.
ShreevatsaR
68
W tym przykładzie łańcuch jest wykonywany jako kod za pomocą funkcji exec.
import sys
importStringIO# create file-like string to capture output
codeOut =StringIO.StringIO()
codeErr =StringIO.StringIO()
code ="""
def f(x):
x = x + 1
return x
print 'This is my output.'
"""# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
exec code
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print f(4)
s = codeErr.getvalue()print"error:\n%s\n"% s
s = codeOut.getvalue()print"output:\n%s"% s
codeOut.close()
codeErr.close()
zamiana stdout i stderr w ten sposób bardzo mnie denerwuje. wygląda na to, że może powodować ogromne problemy z bezpieczeństwem. czy jest na to jakiś sposób?
Narcolapser
1
@Narcolapser powinieneś być bardziej zainteresowany używaniem exec(chyba że wiesz, że ciąg kodu pochodzi z zaufanego źródła).
bruno desthuilliers
27
evali execsą właściwym rozwiązaniem, i można je stosować w bezpieczniejszy sposób.
Jak omówiono w podręczniku Pythona i jasno wyjaśniono w tym samouczku, funkcje evali execpobierają dwa dodatkowe parametry, które pozwalają użytkownikowi określić, jakie globalne i lokalne funkcje i zmienne są dostępne.
Na przykład:
public_variable =10
private_variable =2def public_function():return"public information"def private_function():return"super sensitive information"# make a list of safe functions
safe_list =['public_variable','public_function']
safe_dict = dict([(k, locals().get(k,None))for k in safe_list ])# add any needed builtins back in
safe_dict['len']= len
>>> eval("public_variable+2",{"__builtins__":None}, safe_dict)12>>> eval("private_variable+2",{"__builtins__":None}, safe_dict)Traceback(most recent call last):File"<stdin>", line 1,in<module>File"<string>", line 1,in<module>NameError: name 'private_variable'isnot defined
>>>exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))",{"__builtins__":None}, safe_dict)'public information' has 18 characters
>>>exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))",{"__builtins__":None}, safe_dict)Traceback(most recent call last):File"<stdin>", line 1,in<module>File"<string>", line 1,in<module>NameError: name 'private_function'isnot defined
Zasadniczo definiujesz przestrzeń nazw, w której kod będzie wykonywany.
Nie można uczynić eval bezpiecznym: Eval jest naprawdę niebezpieczny . Jeśli weźmiesz ode mnie kod i sprawdzisz go, mogę segfaultować twój program Python. Koniec gry.
Ned Batchelder,
3
@ v.oddou Odpowiedziałem na oświadczenie Alana: „eval and exec .. można używać w bezpieczny sposób”. To nieprawda. Gdyby ktoś powiedział „bash może być używany w bezpieczny sposób”, byłoby to również fałszywe. Bash jest niebezpieczny. Jest to konieczne niebezpieczeństwo, ale mimo wszystko niebezpieczne. Twierdzenie, że eval można zabezpieczyć, jest po prostu błędne.
Ned Batchelder,
1
@NedBatchelder rzeczywiście tak. a link, który wskazujesz, jest dobrym materiałem. wraz z mocą przychodzi odpowiedzialność, więc chodzi po prostu o świadomość potencjalnej mocy ewaluacji. a jeśli zdecydujemy, że moc = niebezpieczeństwo.
v.oddou
3
@NedBatchelder Wiele fragmentów kodu napisanych w Pythonie może być również niebezpiecznych, ale dlaczego zakładasz, że evallub execmają być używane jako exec(input("Type what you want"))? Istnieje wiele przypadków, w których program może napisać procedurę lub funkcję w wyniku obliczeń; wynikające z tego funkcje będą tak bezpieczne i tak szybkie (raz ocenione), jak każda inna część dobrego i dobrze napisanego programu. Niebezpieczny program zawierający execnie jest bardziej niebezpieczny niż niebezpieczny program sam wyrządzający szkodę, ponieważ execnie daje żadnego nowego przywileju programowi.
Thomas Baruchel
1
@ThomasBaruchel ponownie, moim celem jest przeciwstawienie się temu, że eval lub exec można zabezpieczyć. W szczególności ta odpowiedź twierdzi, że kontrolowanie globali i mieszkańców umożliwi bezpieczne korzystanie z nich. To nieprawda. Za każdym razem, gdy używasz exec i eval, musisz dokładnie wiedzieć, jaki kod jest wykonywany. Jeśli tego nie zrobisz, jesteś otwarty na niebezpieczne operacje.
Ned Batchelder
21
Pamiętaj, że od wersji 3 execjest funkcją!
więc zawsze używaj exec(mystring)zamiast exec mystring.
eval()służy tylko do wyrażeń, podczas gdy eval('x+1')działa, eval('x=1')na przykład nie działa. W takim przypadku lepiej jest użyć exec, a nawet lepiej: spróbuj znaleźć lepsze rozwiązanie :)
Używanie execiw evalPythonie jest bardzo niezadowolone.
Istnieją lepsze alternatywy
Od najwyższej odpowiedzi (moje podkreślenie):
W przypadku wyciągów użyj exec.
Jeśli potrzebujesz wartości wyrażenia, użyj eval.
Jednak pierwszym krokiem powinno być zadanie sobie pytania, czy naprawdę potrzebujesz. Wykonywanie kodu powinno zasadniczo być ostatecznością : jest powolne, brzydkie i niebezpieczne, jeśli może zawierać kod wprowadzony przez użytkownika. Zawsze powinieneś najpierw spojrzeć na alternatywy, takie jak funkcje wyższego rzędu , aby sprawdzić, czy mogą one lepiej zaspokoić twoje potrzeby.
Nie próbuj obchodzić idiomów Pythona, ponieważ jakiś inny język robi to inaczej. Przestrzenie nazw znajdują się w Pythonie z jakiegoś powodu i tylko dlatego, że daje ci narzędzie exec, nie oznacza to, że powinieneś używać tego narzędzia.
Tak więc eval nie jest bezpieczny, nawet jeśli usuniesz wszystkie globals i wbudowane!
Problemem wszystkich tych prób ochrony eval () jest to, że są czarnymi listami . Wyraźnie usuwają rzeczy, które mogą być niebezpieczne. To przegrana bitwa, ponieważ jeśli z listy pozostanie tylko jeden przedmiot, możesz zaatakować system .
Czy więc eval można zabezpieczyć? Ciężko powiedzieć. W tym momencie sądzę, że nie możesz wyrządzić krzywdy, jeśli nie możesz użyć podwójnych znaków podkreślenia, więc może wykluczając dowolny ciąg znaków z podwójnymi znakami podkreślenia, jesteś bezpieczny. Może...
Po pierwsze, execludziom trudniej jest odczytać kod . Aby dowiedzieć się, co się dzieje, nie muszę po prostu czytać twojego kodu, muszę czytać twój kod, dowiedzieć się, jaki ciąg wygeneruje, a następnie przeczytaj ten wirtualny kod. Tak więc, jeśli pracujesz w zespole, publikujesz oprogramowanie typu open source lub prosisz o pomoc w stylu StackOverflow, utrudniasz innym ludziom pomoc. A jeśli istnieje szansa, że za 6 miesięcy będziesz debugować lub rozwijać ten kod, bezpośrednio utrudniasz sobie pracę.
„zgaduję, że nie możesz wyrządzić żadnej krzywdy, jeśli nie możesz użyć podwójnych znaków podkreślenia” - możesz zbudować ciąg zawierający podwójne znaki podkreślenia, a następnie wywołać eval ten ciąg.
Stanley Bak,
dobra rada, chyba że piszesz generator kodu, narzędzie do wykonywania pracy lub podobne ... co większość ludzi tutaj robi.
Erik Aronesty
Muszę zaimportować ścieżkę względną z pliku config ( cfg.yaml): reldir : ../my/dir/ i reldir = cfg[reldir]. Ponieważ jednak ten kod Pythona powinien działać zarówno w systemie Windows, jak i Linux, potrzebuję go, aby dostosować się do różnych dzielników ścieżek systemów operacyjnych; albo \\ albo /. Więc używam reldir : os.path.join('..','my','dir')w pliku konfiguracyjnym. Ale to tylko skutkuje reldirtym, że jest to ciąg literalny, a nie jest oceniany, więc nie mogę otworzyć pliku reldir. Czy masz jakieś sugestie?
Marie. P.
9
Wykonujesz kod za pomocą exec, podobnie jak w przypadku następnej sesji IDLE:
To nie działa w normalnym pythonie. Przynajmniej nie w pythonie 3.
Thomas Ahle,
6
Jak wspomniano inni, jest to „exec” ..
ale w przypadku, gdy kod zawiera zmienne, możesz użyć „globalnego”, aby uzyskać do niego dostęp, aby zapobiec kompilatorowi wywołania następującego błędu:
NameError: nazwa „p_variable” nie jest zdefiniowana
Warto wspomnieć, że ten execbrat istnieje również nazywany, execfilejeśli chcesz wywołać plik python. Czasami jest to dobre, jeśli pracujesz w pakiecie strony trzeciej, który zawiera straszne IDE i chcesz kodować poza jego pakietem.
Najbardziej logicznym rozwiązaniem byłoby użycie wbudowanej funkcji eval (). Innym rozwiązaniem jest zapisanie tego łańcucha do tymczasowego pliku python i wykonanie go.
Ok .. Wiem, że to nie jest dokładnie odpowiedź, ale być może uwaga dla ludzi, którzy patrzą na to tak jak ja. Chciałem wykonać określony kod dla różnych użytkowników / klientów, ale chciałem również uniknąć wykonania / ewaluacji. Początkowo chciałem przechowywać kod w bazie danych dla każdego użytkownika i robić powyższe.
Skończyło się to na tworzeniu plików w systemie plików w folderze „customer_filters” i korzystaniu z modułu „imp”, jeśli dla tego klienta nie zastosowano żadnego filtra, to po prostu kontynuowano
import imp
def get_customer_module(customerName='default', name='filter'):
lm =Nonetry:
module_name = customerName+"_"+name;
m = imp.find_module(module_name,['customer_filters'])
lm = imp.load_module(module_name, m[0], m[1], m[2])except:''#ignore, if no module is found, return lm
m = get_customer_module(customerName,"filter")if m isnotNone:
m.apply_address_filter(myobj)
więc nazwa_klienta = „jj” wykona filtr_pliku_zastosowania z pliku filtry_klienta \ jj_filter.py
Odpowiedzi:
W przypadku instrukcji użyj
exec(string)
(Python 2/3) lubexec string
(Python 2):Jeśli potrzebujesz wartości wyrażenia, użyj
eval(string)
:Jednak pierwszym krokiem powinno być zadanie sobie pytania, czy naprawdę potrzebujesz. Wykonywanie kodu powinno zasadniczo być ostatecznością: jest powolne, brzydkie i niebezpieczne, jeśli może zawierać kod wprowadzony przez użytkownika. Zawsze powinieneś najpierw spojrzeć na alternatywy, takie jak funkcje wyższego rzędu, aby sprawdzić, czy mogą one lepiej zaspokoić twoje potrzeby.
źródło
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
itp., Które może następnie zapisać jakoexec ("x.%s = 42" % s)
. W tym typowym przypadku (gdy potrzebujesz tylko dostępu do atrybutu obiektu przechowywanego w ciągu), istnieje znacznie szybsza, czystsza i bezpieczniejsza funkcjagetattr
: po prostu pisz,getattr(x, s) = 42
aby oznaczać to samo.setattr(x, s, 42)
? Próbowałemgetattr(x, 2) = 42
i nie udało sięcan't assign to function call: <string>, line 1
setattr(x, s, 42)
jest poprawna składnia. Zaskoczony, że tak długo zajęło wykrycie tego błędu. W każdym razie chodzi o to, żegetattr
isetattr
są alternatywą dlaexec
kiedy chcesz to dostać dowolny element, spojrzał w górę przez struny.W tym przykładzie łańcuch jest wykonywany jako kod za pomocą funkcji exec.
źródło
exec
(chyba że wiesz, że ciąg kodu pochodzi z zaufanego źródła).eval
iexec
są właściwym rozwiązaniem, i można je stosować w bezpieczniejszy sposób.Jak omówiono w podręczniku Pythona i jasno wyjaśniono w tym samouczku, funkcje
eval
iexec
pobierają dwa dodatkowe parametry, które pozwalają użytkownikowi określić, jakie globalne i lokalne funkcje i zmienne są dostępne.Na przykład:
Zasadniczo definiujesz przestrzeń nazw, w której kod będzie wykonywany.
źródło
eval
lubexec
mają być używane jakoexec(input("Type what you want"))
? Istnieje wiele przypadków, w których program może napisać procedurę lub funkcję w wyniku obliczeń; wynikające z tego funkcje będą tak bezpieczne i tak szybkie (raz ocenione), jak każda inna część dobrego i dobrze napisanego programu. Niebezpieczny program zawierającyexec
nie jest bardziej niebezpieczny niż niebezpieczny program sam wyrządzający szkodę, ponieważexec
nie daje żadnego nowego przywileju programowi.Pamiętaj, że od wersji 3
exec
jest funkcją!więc zawsze używaj
exec(mystring)
zamiastexec mystring
.źródło
eval()
służy tylko do wyrażeń, podczas gdyeval('x+1')
działa,eval('x=1')
na przykład nie działa. W takim przypadku lepiej jest użyćexec
, a nawet lepiej: spróbuj znaleźć lepsze rozwiązanie :)źródło
Unikaj
exec
ieval
Używanie
exec
iweval
Pythonie jest bardzo niezadowolone.Istnieją lepsze alternatywy
Od najwyższej odpowiedzi (moje podkreślenie):
Od alternatyw do exec / eval?
To nie jest idiomatyczne
From http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (moje podkreślenie)
To jest niebezpieczne
From http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (moje podkreślenie)
Trudno to przeczytać i zrozumieć
From http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (moje podkreślenie):
źródło
cfg.yaml
):reldir : ../my/dir/
ireldir = cfg[reldir]
. Ponieważ jednak ten kod Pythona powinien działać zarówno w systemie Windows, jak i Linux, potrzebuję go, aby dostosować się do różnych dzielników ścieżek systemów operacyjnych; albo\\
albo/
. Więc używamreldir : os.path.join('..','my','dir')
w pliku konfiguracyjnym. Ale to tylko skutkujereldir
tym, że jest to ciąg literalny, a nie jest oceniany, więc nie mogę otworzyć plikureldir
. Czy masz jakieś sugestie?Wykonujesz kod za pomocą exec, podobnie jak w przypadku następnej sesji IDLE:
źródło
Jak wspomniano inni, jest to „exec” ..
ale w przypadku, gdy kod zawiera zmienne, możesz użyć „globalnego”, aby uzyskać do niego dostęp, aby zapobiec kompilatorowi wywołania następującego błędu:
źródło
Użyj eval .
źródło
Warto wspomnieć, że ten
exec
brat istnieje również nazywany,execfile
jeśli chcesz wywołać plik python. Czasami jest to dobre, jeśli pracujesz w pakiecie strony trzeciej, który zawiera straszne IDE i chcesz kodować poza jego pakietem.Przykład:
execfile('/path/to/source.py)'
lub:
exec(open("/path/to/source.py").read())
źródło
Sprawdź eval :
źródło
Próbowałem całkiem sporo rzeczy, ale jedyne, co zadziałało, to:
wynik:
10
źródło
Najbardziej logicznym rozwiązaniem byłoby użycie wbudowanej funkcji eval (). Innym rozwiązaniem jest zapisanie tego łańcucha do tymczasowego pliku python i wykonanie go.
źródło
Ok .. Wiem, że to nie jest dokładnie odpowiedź, ale być może uwaga dla ludzi, którzy patrzą na to tak jak ja. Chciałem wykonać określony kod dla różnych użytkowników / klientów, ale chciałem również uniknąć wykonania / ewaluacji. Początkowo chciałem przechowywać kod w bazie danych dla każdego użytkownika i robić powyższe.
Skończyło się to na tworzeniu plików w systemie plików w folderze „customer_filters” i korzystaniu z modułu „imp”, jeśli dla tego klienta nie zastosowano żadnego filtra, to po prostu kontynuowano
więc nazwa_klienta = „jj” wykona filtr_pliku_zastosowania z pliku filtry_klienta \ jj_filter.py
źródło