2011-01-21 17 views
7

powiedzmy, mam pewien zakres ze zmiennych, a funkcja nazywa się w tym zakresie chce zmienić kilka zmiennych niezmienne:Dostęp zakresu zewnętrzną w Pythonie 2.6

 
def outer(): 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(): 
    s = 'abcd' 
    n = 456 

jest to możliwe w jakiś sposób, aby uzyskać dostęp zakresu zewnętrzną? Coś jak zmienne z Py3k.

W tym przypadku mogę zrobić s,n = modify(s,n), ale co, jeśli potrzebuję jakiegoś ogólnego "zastrzyku", który tam wykonuje i musi mieć możliwość przypisania do dowolnych zmiennych?

Mam wydajność w umyśle, więc jeśli to możliwe, eval inspekcja rama & stos nie jest mile widziany :)


UPD: To niemożliwe. Kropka. Istnieje jednak kilka opcji uzyskiwania dostępu do zmiennych w zakresie zewnętrznym:

  1. Użyj globaliów. Nawiasem mówiąc, func.__globals__ jest zmienny słowniku;)
  2. zmienne przechowywać w dict/klasa instancji/wszelkie inne zmienne pojemnik
  3. Daj zmienne jako argumenty & dostać je z powrotem jako krotki: a,b,c = innerfunc(a,b,c)
  4. Inject inna funkcja użytkownika kod bajtowy. Jest to możliwe dzięki pytonowi byteplay.
+1

To nie działa jak skopiuj. Pytasz o dostęp do zakresu na innej ramie stosu. Byłoby to ** bardzo ** mylące jeśli scoping pozwoliłby na to co tu wypróbujesz, pomyśl o przepisaniu rekursji ogona na pętle. Więc optymalizacja kodu nagle zmieni znaczenie programu, nigdy tak się nie stanie. – Tino

Odpowiedz

3

To nie how nonlocal prace. Nie zapewnia dynamicznego określania zakresu (co jest po prostu ogromną PITA oczekującą na zdarzenie, a jeszcze rzadziej użyteczną od przeciętnej "zła"). Po prostu poprawia definicję leksykalną.

W każdym razie nie możesz zrobić tego, co masz na myśli (i powiedziałbym, że to dobrze). Nie ma nawet brudnego, ale łatwego hackowania (a gdy jesteśmy przy tym: takie hacki nie są zniechęcane, ponieważ generalnie działają nieco gorzej!). Po prostu zapomnij o tym i rozwiązaj prawdziwy problem (nie nazwałeś go, więc nie możemy nic na ten temat powiedzieć).

Najbliższym możliwym do uzyskania jest zdefiniowanie obiektu, który przenosi wszystko, co chcesz udostępnić, i przekazanie go w sposób jawny (np. Utwórz klasę i użyj self, jak zasugerowano w innej odpowiedzi). Ale jest to dość uciążliwe, aby robić to wszędzie i wciąż hackery (choć lepsze niż dynamiczne określanie zakresu, ponieważ "wyraźna jest lepsza niż niejawna").

7

Definiuj zmienne poza funkcjami i użyj słowa kluczowego global.

s, n = "", 0 

def outer(): 
    global n, s 
    n = 123 
    s = 'qwerty' 
    modify() 

def modify(): 
    global n, s 
    s = 'abcd' 
    n = 456 
+1

Zamień 'i' na' xor', aby działało. Przepisz od podstaw, aby uzyskać dobrą radę. – delnan

+0

@delnan, przepraszam, ale ??? – orlp

+0

Oznacza "zdefiniuj je na zewnątrz lub użyj" globalnego ", ale nie obu". – gotgenes

3

Twoje opcje są do korzystania global zmienne

s = None 
n = None 

def outer(self): 
    global s 
    global n 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(self): 
    global s 
    global n 
    s = 'abcd' 
    n = 456 

lub zdefiniować je jako metody i użyć zmiennej klasy lub instancji.

class Foo(object): 
    def __init__(self): 
     self.s = None 
     self.n = None 

    def outer(self): 
     self.s = 'qwerty' 
     self.n = 123 
     self.modify() 

    def modify(self): 
     self.s = 'abcd' 
     self.n = 456 
7

Czasami używam kodu podobnego do tego.Funkcja zagnieżdżona modyfikuje zmienny obiekt zamiast przypisywania do nonlocal:

def outer(): 
    s = [4] 
    def inner(): 
     s[0] = 5 
    inner() 
+1

To interesujące. Brzydki, ale interesujący. – gotgenes

+1

'outer.s = 4' itd. –

+3

Możesz wpisać outer.s = 4, ale to przypisze atrybut funkcji outer(). Nie jest to to samo, co przypisanie zmiennej lokalnej o nazwie s. – joeforker

1

prawdopodobnie można też to zrobić (nie mówiąc, że to jest po prawej);

zdefiniować funkcję, która zwraca tablicę z wierszy jak tak

["a = qwerty","n = 123"] 

Następnie zrobić w zakresie potrzebne są vars

for row in array: 
    eval(row) 

tego jest cholernie hacky chociaż.

+0

Myślę, że masz na myśli 'exec (row)'; eval jest tylko dla wyrażeń – Ord

Powiązane problemy