2013-02-23 37 views
5

Tôi đã học Ruby và Python đồng thời và một trong những điều tôi nhận thấy là 2 ngôn ngữ này dường như đối xử với phạm vi khác nhau. Dưới đây là ví dụ về ý tôi:Phạm vi trong Ruby và Python

# Python 
a = 5 
def myfunc(): 
    print a 

myfunc() # => Successfully prints 5 

# Ruby 
a = 5 
def myfunc 
    puts a 
end 

myfunC# => Throws a "NameError: undefined local variable or method `a' for main:Object" 

Dường như khối def có thể truy cập các biến được khai báo ngoài phạm vi ngay lập tức bằng Python nhưng không phải trong Ruby. Ai đó có thể xác nhận liệu sự hiểu biết của tôi có đúng không? Và nếu có, liệu một trong những cách suy nghĩ về phạm vi này có phổ biến hơn trong lập trình không?

+0

Đối với phía Python, bạn nói đúng (rõ ràng là có nhiều hơn để phạm vi, nhưng cách viết của bạn không mâu thuẫn với nó). – delnan

+0

Câu trả lời bằng Python có thể có tại đây: http://stackoverflow.com/questions/370357/python-variable-scope-question –

Trả lời

4

Disclaimer: Tôi không phải chuyên gia python

Trong python, nơi các biến định nghĩa trong một module là, theo mặc định, các biến mô-đun và như toàn cầu như vậy để mô-đun đó. Trong Ruby, khi bạn định nghĩa một biến thường, nó luôn luôn là một biến cục bộ. Các biến cục bộ chỉ có thể truy cập được trong khối đã định nghĩa chúng và trong procs/lambdas được định nghĩa trong khối bao bọc biến đó.

Trong Ruby, cho một biến để vượt qua phạm vi, nó cần phải được một trong hai:

  • Một hằng số (ALL_CAPS): Luôn luôn sử dụng được, nếu bắt đầu bằng phạm vi đúng
  • biến Class (@@double_at): Luôn truy cập từ lớp xác định và bất kỳ lớp con nào, nhưng không phải từ bên ngoài
  • Biến cá thể (@single_at): Chỉ truy cập được từ bên trong đối tượng đó và từ bên ngoài bằng phương thức getter/get_instance_variable.
  • Toàn cầu ($starts_with_dollar): Ý tưởng tồi. Crosses tất cả các phạm vi, không có phạm vi cần thiết. Không được dùng!
+0

Tôi thấy, vì vậy đối với Python, khi bạn định nghĩa một biến bên ngoài bất kỳ lớp hoặc khối nào, theo mặc định nó sẽ nằm trong phạm vi toàn cục. Điều này trái ngược với Ruby, nơi Ruby xử lý từng phạm vi như một thực thể riêng biệt của nó và bạn xác định các biến toàn cầu có thể truy cập trong tất cả các phạm vi thông qua việc sử dụng $. Đó có phải là một bản tóm tắt chính xác không? – wmock

+0

@WillsonMock: Khá nhiều. – Linuxios

+2

Nitor nhỏ: hằng số không phải là ALL_CAPS, chúng chỉ bắt đầu bằng chữ viết hoa. Ví dụ, các tên lớp là các hằng số. – steenslag

1

Trong Ruby nếu bạn muốn truy cập một biến được định nghĩa bên ngoài phương thức bạn đang gọi, bạn cần xác định nó là toàn cục. Ruby cố gắng phù hợp với biến được định nghĩa trong phạm vi cục bộ, nếu không tìm thấy nó, hãy ném một ngoại lệ.

Bạn có thể xác định biến toàn cầu với ký hiệu $.

$a = 5 
def myfunc 
    puts $a 
end 

myfunc 

Tuy nhiên, nguyên tắc chung không phải là cách hay để xác định các biến toàn cầu nếu không sẽ có nguy cơ gây ô nhiễm không gian tên chung.

+3

Điều này là không đúng. Một biến cá thể ('@ a') là đủ. – steenslag

1

Bạn có thể sử dụng mô-đun dis để xem Python đang làm gì.

import dis 

a = 5 
def myfunc(): 
    print a 

Kết quả:

>>> dis.dis(myfunc) 
15   0 LOAD_GLOBAL    0 (a) 
       3 PRINT_ITEM   
       4 PRINT_NEWLINE  
       5 LOAD_CONST    0 (None) 
       8 RETURN_VALUE 

Vì vậy, bạn có thể thấy rằng a là trong phạm vi toàn cầu.