2011-01-21 41 views
7

Này, tôi có một số phạm vi với các biến, và một chức năng gọi là trong phạm vi này muốn thay đổi một số biến bất biến:Truy cập phạm vi bên ngoài trong Python 2.6

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

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

Có thể bằng cách nào đó để truy cập vào phạm vi bên ngoài? Một cái gì đó như nonlocal biến từ Py3k.

Chắc chắn tôi có thể làm s,n = modify(s,n) trong trường hợp này, nhưng điều gì sẽ xảy ra nếu tôi cần một số 'tiêm' chung thực hiện ở đó và phải có khả năng phân công lại cho các biến tùy ý?

tôi có hiệu suất trong tâm trí, vì vậy, nếu có thể, eval & chồng kiểm tra khung không được chào đón :)


UPD: Đó là bất khả thi. Giai đoạn. Tuy nhiên, có một số tùy chọn cách truy cập các biến trong phạm vi bên ngoài:

  1. Sử dụng hình cầu. Bằng cách này, func.__globals__ là một cuốn từ điển có thể thay đổi;)
  2. Lưu trữ các biến trong một dict/lớp sơ thẩm/bất kỳ container có thể thay đổi khác
  3. Cho biến như các đối số & nhận được chúng trở lại như một tuple: a,b,c = innerfunc(a,b,c)
  4. Tiêm khác chức năng của bytecode. Điều này là có thể với mô-đun python byteplay.
+1

Đó không phải là cách hoạt động của phạm vi. Bạn yêu cầu truy cập một phạm vi trên một stackframe khác nhau. Nó sẽ được ** rất ** khó hiểu nếu phạm vi sẽ cho phép những gì bạn cố gắng ở đây, suy nghĩ của đệ quy đuôi được viết lại thành vòng lặp. Vì vậy, tối ưu hóa mã đột nhiên sẽ thay đổi ý nghĩa của một chương trình, điều này sẽ không bao giờ xảy ra. – Tino

Trả lời

3

Đây là không cách nonlocal công trình. Nó không cung cấp phạm vi động (mà chỉ là một PITA lớn đang chờ xảy ra và thậm chí hiếm khi hữu ích hơn tính năng "ác" trung bình của bạn). Nó chỉ sửa chữa phạm vi từ vựng.

Dù sao, bạn không thể làm những gì bạn có trong tâm trí (và tôi sẽ nói rằng đây là một điều tốt). Thậm chí không có một hack bẩn nhưng dễ dàng (và trong khi chúng tôi đang ở đó: hack như vậy không được khuyến khích bởi vì họ thường thực hiện một chút tồi tệ hơn!). Chỉ cần quên nó và giải quyết vấn đề thực sự đúng (bạn đã không đặt tên nó, vì vậy chúng tôi không thể nói bất cứ điều gì về điều này).

Gần nhất bạn có thể nhận được là xác định một số đối tượng chứa mọi thứ bạn muốn chia sẻ và chuyển nó một cách rõ ràng (ví dụ: tạo lớp và sử dụng self, như được đề xuất trong câu trả lời khác). Nhưng đó là tương đối cồng kềnh để làm ở khắp mọi nơi, và vẫn còn hackery (mặc dù tốt hơn so với phạm vi năng động, bởi vì "rõ ràng là tốt hơn so với ngầm").

7

Xác định các biến bên ngoài các chức năng và sử dụng từ khóa global.

s, n = "", 0 

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

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

Thay thế 'và' bằng' xor' để làm việc này. Viết lại từ đầu để được tư vấn tốt. – delnan

+0

@delnan, tôi xin lỗi, nhưng ??? – orlp

+0

Ông có nghĩa là "xác định chúng bên ngoài, hoặc sử dụng' toàn cầu', nhưng không phải cả hai ". – gotgenes

3

lựa chọn của bạn là để sử dụng global biến,

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 

hoặc xác định những người như phương pháp và sử dụng một biến lớp học hoặc ví dụ.

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

Đôi khi tôi chạy trên mã như thế này.Một chức năng lồng nhau sẽ thay đổi một đối tượng có thể thay đổi thay vì gán cho một nonlocal:

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

Điều đó thật thú vị. Xấu xí, nhưng thú vị. – gotgenes

+1

'outer.s = 4' etc –

+3

Bạn có thể gõ outer.s = 4, nhưng điều đó sẽ gán một thuộc tính cho hàm outer(). Nó không giống như gán cho biến cục bộ được gọi là s. – joeforker

1

Bạn có thể có lẽ cũng làm được điều này (không nói nó là đúng);

xác định một hàm trả về một mảng với hàng như vậy

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

Sau đó làm trong phạm vi bạn cần vars

for row in array: 
    eval(row) 

này là khá darn hacky mặc dù.

+0

Tôi nghĩ bạn có nghĩa là 'exec (hàng)'; eval chỉ dành cho các biểu thức – Ord

Các vấn đề liên quan