2011-12-30 37 views
6

Mã in sau 123:Biến miễn phí Python. Tại sao điều này không thành công?

>>> a = 123 
>>> def f(): 
...  print a 
... 
>>> f() 
123 
>>> 

Nhưng sau thất bại:

>>> a = 123 
>>> def f(): 
...  print a 
...  a = 456 
...  print a 
... 
>>> f() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in f 
UnboundLocalError: local variable 'a' referenced before assignment 
>>> 

tôi dự kiến ​​sẽ có này để in:

123 
456 

tôi đang thiếu gì ở đây?

P.S. Tôi đang sử dụng Python 2.6.6 nếu có vấn đề.

+0

Không có tham số để cung cấp tham chiếu biến cho phương thức, bạn sẽ phải dựa vào 'a' để khai báo trong mã, trước khi gọi hàm' f() 'chỉ để' in a' ở nơi đầu tiên. Tác dụng phụ rất nhiều. – Droogans

+0

Tôi đã thêm một giải pháp cho vấn đề của bạn, nhưng theo cách thông thường, bạn chỉ muốn tránh việc viết gần. Chỉ cần tạo một biến trung gian và trả về kết quả. –

Trả lời

7

Nếu một hàm chỉ đọc từ một biến, nó được giả định là toàn cục. Nếu hàm ghi vào nó bao giờ, nó được giả định là cục bộ. Trong hàm thứ hai của bạn, một hàm được ghi vào, do đó nó được giả định là cục bộ. Sau đó, dòng ở trên (nơi mà nó đọc từ) không hợp lệ.

Dưới đây là một liên kết đến FAQ Python: http://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

+0

OK, nhưng không phải là Python đã diễn giải? Tôi hy vọng bản in sẽ hoạt động sau đó không thành công khi tôi thử phép gán (vì tôi sẽ gán cho một biến toàn cục mà không có khai báo 'global'). Tại sao nó thất bại trên bản in chứ không phải là sự xác nhận? – ElenaT

+2

Python được biên dịch. Nó chỉ là nó biên dịch sang bytecode, để chạy trên một máy ảo (nghĩa là chính xác như Java) –

+0

Python được biên dịch thành mã byte khi chạy.Khi một hàm được biên dịch, trình biên dịch xác định tên nào là người dân địa phương là các hình cầu nào (và các thứ khác, như thể hàm này thực sự là một trình tạo ra khi nó chứa các câu lệnh lợi nhuận). –

4

Đó là vì Python tự động hoạt động như biến là toàn cầu trừ khi bạn xác định hoặc cố gắng sửa đổi nó trong hàm. Thử thêm global a vào mã của bạn.

>>> a = 123 
>>> def f(): 
...  global a 
...  print a 
...  a = 456 
...  print a 
... 
>>> f() 
123 
456 
>>> a 
456 

Trong ví dụ đầu tiên bạn không xác định và không sửa đổi, vì vậy, đây là ví dụ toàn cầu. Nhưng nếu bạn muốn, ví dụ, thêm 20 vào một, bạn cũng phải sử dụng global a.

Cũng cần lưu ý rằng hàm a trong f là toàn cầu và giá trị của nó sẽ khác sau khi chạy hàm f.

Nếu bạn muốn tạo biến cục bộ, hãy nhớ, khai báo đó luôn đi trước khi đọc, vì vậy không thể thực hiện print a trước a = 456.

EDIT: Ok, trong khi chúng ta đang nói về việc đóng cửa và nguy hiểm khi sử dụng toàn cầu thì có khả năng khác.

>>> a = 123 
>>> def f(): 
...  b = a 
...  print b 
...  b = 456 
...  print b 
... 
>>> f() 
123 
456 
>>> a 
123 
>>> 

Ở đây chúng ta sử dụng một đóng cửa chỉ đọc khả năng để thực hiện một bản sao của a và hơn sửa đổi bản sao này, mà không modifing các a biến bên ngoài AS miễn là nó là INTEGER. Hãy nhớ rằng, b giữ một tham chiếu đến a. Ví dụ: nếu a, danh sách và hoạt động f giống như b.append(3) thì cả ab sẽ có sẵn và được sửa đổi ngoài phạm vi.

Lựa chọn phương pháp khác nhau tùy theo nhu cầu.

+0

Không phải là không. Bạn sẽ có cùng một vấn đề nếu bạn làm cùng một mã trong một phương thức. Sử dụng toàn cầu sau đó sẽ nguy hiểm, bạn sẽ nhận được biến của lớp nếu nó tồn tại. –

+0

Tôi đã áp dụng khách hàng tiềm năng của mình trong bản chỉnh sửa câu trả lời. – Gandi

+0

Cảm ơn, chuyển đổi -1 thành +1 –

5

gì bạn đang sử dụng được đặt tên theo một closure: bạn hãy biến khỏi phạm vi outter và kèm theo trong một khối chức năng.

Mã của bạn hoàn toàn ổn, và sẽ hoạt động trong javascript.

Thật không may, trong Python, đóng cửa là chỉ đọc.

Và lỗi luôn là UnboundLocalError: local variable 'var_name' referenced before assignment hoàn toàn gây hiểu nhầm.

Viết tắt, đây không phải là bạn, đó là giới hạn ngôn ngữ kết hợp với thông báo lỗi xấu.

EDIT:

tôi có thể nhìn thấy một số người ở đây ủng hộ việc sử dụng global, trong đó có các tác dụng phụ nguy hiểm: bạn sẽ nhận được quyền truy cập vào các biến có cùng tên một vài phạm vi trên một hiện tại, mà không phải là những gì bạn muốn với bao đóng.

Giải pháp đã được thêm vào trong Python 3, với từ khóa nonlocal thực hiện chính xác điều đó: rebind biến từ phạm vi bên ngoài trong phạm vi bên trong. Có một cách để simulate nonlocal for python 2.x, nhưng thực sự bạn tốt hơn chỉ cần không chỉ định bất cứ điều gì để biến của bạn: giá trị sao chép, giá trị trả lại, sửa đổi tại chỗ chỉ có thể loại mutable và bạn sẽ được sử dụng tốt.

+0

Không biết đóng cửa là chỉ đọc. Có bất kỳ hạn chế nào khác đối với việc đóng cửa Python không? Tôi có thể tìm thêm thông tin ở đâu? (trên các giới hạn) – ElenaT

+0

+1 để đề cập đến việc đóng chỉ đọc. – sinan

+0

Nếu lỗi là việc đóng cửa là chỉ đọc, sẽ không xảy ra lỗi trên đường chuyển nhượng chứ không phải là lệnh in? –

0

Không gian nhận xét quá nhỏ để vừa với các dấu ngoặc kép bên dưới, vì vậy tôi đăng câu trả lời mới tại đây.

Tôi nghĩ đây là vấn đề phạm vi biến. Trong Execution Model của Python doc nó nói:

Nếu một tên hoạt động ràng buộc xảy ra bất cứ nơi nào trong một khối mã, tất cả sử dụng của tên trong khối được coi là tài liệu tham khảo cho các khối hiện . Điều này có thể dẫn đến lỗi khi tên được sử dụng trong khối trước khi bị ràng buộc. Quy tắc này là tinh tế. Python thiếu các khai báo và cho phép các hoạt động liên kết tên xảy ra ở bất cứ đâu trong khối mã. Các biến cục bộ của một khối mã có thể là được xác định bằng cách quét toàn bộ văn bản của khối cho các ràng buộc tên hoạt động.

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