2012-10-02 23 views
52

Lý do có hàm globals() trong Python là gì? Nó chỉ trả về từ điển của các biến toàn cầu, mà đã được toàn cầu, vì vậy chúng có thể được sử dụng ở bất cứ đâu ... Tôi chỉ hỏi tò mò, cố gắng tìm hiểu python.Lý do cho globals() bằng Python?

def F(): 
    global x 
    x = 1 

def G(): 
    print(globals()["x"]) #will return value of global 'x', which is 1 

def H(): 
    print(x) #will also return value of global 'x', which, also, is 1 

F() 
G() 
H() 

Tôi thực sự không thể thấy điểm ở đây? Chỉ có thời gian tôi sẽ cần đến nó, là nếu tôi đã biến địa phương và toàn cầu, với cùng một tên cho cả hai

def F(): 
    global x 
    x = 1 

def G(): 
    x = 5 
    print(x) #5 
    print(globals()["x"]) #1 

F() 
G() 

Nhưng bạn không bao giờ nên chạy vào một vấn đề của việc có hai biến với cùng một tên, và cần phải sử dụng cả hai đều trong phạm vi tương tự.

+2

"Nhưng bạn không bao giờ nên gặp phải vấn đề về việc có hai biến có cùng tên và cần phải sử dụng cả hai biến đó trong cùng một phạm vi". Tôi không thể làm theo suy nghĩ này. Đó là toàn bộ lý do cho các không gian tên riêng biệt, rằng bạn có các biến có cùng tên trong các phạm vi khác nhau. Khi bạn làm việc với hai trong số họ, tên trùng lặp là một điều tự nhiên, nhưng không phải là một vấn đề, như bạn có thể tiền tố chúng. – Michael

+0

Tôi cũng đến từ gia đình C++, vì vậy tôi không chắc chắn về người Python, nhưng theo như tôi có thể nghĩ đến, bạn không nên có một ** toàn cầu ** biến mà không có một tên duy nhất. Chắc chắn sẽ có các biến có cùng tên, trong cùng một phạm vi, đó là câu ngu ngốc từ tôi, nhưng không phải là các hình cầu có cùng tên với các tên địa phương. Đó là khi tôi sử dụng không gian tên cho những người địa phương ... Nhưng không biết, nếu bạn nói như vậy. –

+3

@Mahi: 'globals' có lẽ là một chút gây hiểu lầm. 'globals()' về cơ bản là 'local()' của một module.Python gần nhất đến các globals thực sự toàn cầu cho tất cả chương trình của bạn là ['__builtin__' module] (http://docs.python.org/library/__builtin__.html); bất cứ thứ gì bạn thêm vào * mô đun * đó sẽ có sẵn trong tất cả các không gian tên ở khắp mọi nơi. –

Trả lời

71

Python cung cấp cho trình lập trình một số lượng lớn các công cụ để tìm hiểu môi trường đang chạy. globals() chỉ là một trong số đó, và nó có thể rất hữu ích trong một phiên gỡ lỗi để xem những đối tượng phạm vi toàn cầu thực sự chứa.

Lý do đằng sau nó, tôi chắc chắn, giống như sử dụng locals() để xem các biến được xác định trong hàm hoặc sử dụng dir để xem nội dung của mô-đun hoặc thuộc tính của đối tượng.

Đến từ nền C++, tôi có thể hiểu rằng những thứ này có vẻ không cần thiết. Trong môi trường tĩnh được liên kết tĩnh, chúng hoàn toàn sẽ là. Trong trường hợp đó, nó được biết tại thời gian biên dịch chính xác những biến nào là toàn cầu, và các thành viên nào một đối tượng sẽ có, và thậm chí cả những tên được xuất khẩu bởi một đơn vị biên dịch khác.

Tuy nhiên, bằng ngôn ngữ động, những thứ này không cố định; chúng có thể thay đổi tùy thuộc vào cách mã được nhập hoặc thậm chí trong thời gian chạy. Vì lý do đó ít nhất, việc truy cập vào loại thông tin này trong trình gỡ lỗi có thể là vô giá.

+9

+1. Ngoài ra, từ điển được trả về bởi 'globals' có thể được sửa đổi (có thể là một khả năng tốt nhất còn lại cho các chuyên gia). Cũng có liên quan là trích dẫn này từ [Dive Into Python] (http://www.diveintopython.net/html_processing/locals_and_globals.html) "Sử dụng các hàm' localals' và 'globals', bạn có thể nhận giá trị của các biến tùy ý một cách tự động, cung cấp tên biến như một chuỗi. Điều này phản ánh chức năng của hàm 'getattr', cho phép bạn truy cập các hàm tùy ý một cách động bằng cách cung cấp tên hàm dưới dạng chuỗi." –

+1

Không nói câu trả lời của bạn là tốt hơn của người khác, nhưng đối với tôi nó là. Cảm ơn, tôi đoán tôi cần phải bình tĩnh và nhớ rằng Python không phải là C + + :) Và cảm ơn cho tất cả mọi người khác trả lời quá, xóa khá nhiều. –

+0

Thay đổi các yếu tố ở người dân địa phương() thường không hiệu quả. Hầu hết các hàm python không có một dict cho người dân địa phương - vì vậy khi bạn gọi người dân địa phương() nó xây dựng một dict của các giá trị hiện tại của người dân địa phương; thay đổi mà dict không phản ánh người dân địa phương. Có những trường hợp mà các chức năng đã làm những việc như "import * from xyz" (không còn được cho phép) - đặt những người dân địa phương với những cái tên chưa biết tại thời gian biên dịch; những chức năng đó được biên dịch với một người dân địa phương thực sự, từ lâu, * tất cả * chức năng đã có một người dân địa phương thực tế dict, và họ đã loại bỏ sự cần thiết cho điều đó, tôi không biết theo những điều kiện bạn có một dict bây giờ. – greggo

5

globals() hữu ích cho eval() - nếu bạn muốn đánh giá một số mã đề cập đến các biến trong phạm vi, các biến đó sẽ nằm trong các hình ảnh tổng quát hoặc địa phương.


Để mở rộng một chút, hàm dựng sẵn eval() sẽ diễn giải một chuỗi mã Python được cung cấp cho nó. Chữ ký là: eval(codeString, globals, locals), và bạn sẽ sử dụng nó như vậy:

def foo(): 
    x = 2 
    y = eval("x + 1", globals(), locals()) 
    print("y=" + y) # should be 3 

này hoạt động, bởi vì người phiên dịch được giá trị của x từ locals() dict của các biến. Tất nhiên bạn có thể cung cấp dict của riêng bạn của các biến để eval.

+1

Downvoter: xin vui lòng giải thích trong một bình luận. –

+0

Tôi không phải là một trong những downvoting, nhưng điều đó không thực sự có ý nghĩa, bạn có thể cho một mã ví dụ cho sự hiểu biết dễ dàng hơn? –

+0

Chắc chắn, tôi đã mở rộng câu trả lời của mình. –

7

Bạn có thể chuyển kết quả của globals()locals() tới các lệnh eval, execfile__import__. Làm như vậy tạo ra một môi trường hạn chế cho các lệnh đó hoạt động.

Do đó, các chức năng này tồn tại để hỗ trợ các chức năng khác được hưởng lợi từ môi trường có khả năng khác với ngữ cảnh hiện tại. Ví dụ: bạn có thể gọi globals() rồi xóa hoặc thêm một số biến trước khi gọi một trong các hàm đó.

30

Nó cũng hữu ích khi bạn cần gọi hàm bằng cách sử dụng tên chuỗi của hàm. Ví dụ:

def foo(): 
    pass 

function_name_as_string = 'foo' 

globals()[function_name_as_string]() # foo(). 
+3

Tôi hiểu. Đó có phải là một thực hành tốt? –

+0

Điều gì xảy ra nếu hàm có nhiều tham số như, def foo (a, b, c = false). Làm thế nào bạn sẽ vượt qua những tham số để globals() – ksooklall

+0

@ksooklall Bạn vượt qua nó vào chức năng như bình thường: với 'def foo (* args): in (" hw ", * args)' bạn có thể làm: 'globals() [ 'foo']() 'hoặc' globals() ['foo'] ('lý do', 42) 'v.v. – Tino

0

Nó có thể hữu ích trong 'python khai báo'.Ví dụ, ở bên dưới FooDefBarDef là các lớp được sử dụng để xác định một loạt các cấu trúc dữ liệu mà sau đó được sử dụng bởi một số gói làm đầu vào của nó hoặc cấu hình của nó. Điều này cho phép bạn rất linh hoạt trong những gì đầu vào của bạn, và bạn không cần phải viết một trình phân tích cú pháp.

# FooDef, BarDef are classes 

Foo_one = FooDef("This one", opt1 = False, valence = 3) 
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one) 

namelist = [] 
for i in range(6): 
    namelist.append("nm%03d"%i) 

Foo_other = FooDef("a third one", string_list = namelist) 

Bar_thing = BarDef((Foo_one, Foo_two), method = 'depth-first') 

Lưu ý rằng tệp cấu hình này sử dụng vòng lặp để tạo danh sách tên là một phần của cấu hình Foo_other. Vì vậy, ngôn ngữ cấu hình này đi kèm với một 'preprocessor' rất mạnh, với một thư viện thời gian chạy có sẵn. Trong trường hợp bạn muốn tìm kiếm một bản ghi phức tạp hoặc trích xuất mọi thứ từ một tệp zip và giải mã base64, như là một phần của việc tạo cấu hình của bạn (tất nhiên, phương pháp này không được khuyến nghị trong trường hợp đầu vào có thể từ nguồn không tin cậy ...)

các gói phần mềm đọc cấu hình sử dụng giống như sau:

conf_globals = {} # make a namespace 
# Give the config file the classes it needs 
conf_globals['FooDef']= mypkgconfig.FooDef # both of these are based ... 
conf_globals['BarDef']= mypkgconfig.BarDef # ... on .DefBase 

fname = "user.conf" 
try: 
    exec open(fname) in conf_globals 
except Exception: 
    ...as needed... 
# now find all the definitions in there 
# (I'm assuming the names they are defined with are 
# significant to interpreting the data; so they 
# are stored under those keys here). 

defs = {} 
for nm,val in conf_globals.items(): 
    if isinstance(val,mypkgconfig.DefBase): 
     defs[nm] = val 

Vì vậy, cuối cùng nhận được đến điểm, globals() là hữu ích, khi sử dụng một gói phần mềm như vậy, nếu bạn muốn đúc một loạt các định nghĩa theo thủ tục:

for idx in range(20): 
    varname = "Foo_%02d" % i 
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i) 

này tương đương với viết ra

Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1) 
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2) 
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4) 
... 17 more ... 

Một ví dụ về một gói mà có được đầu vào của nó bằng cách thu thập một loạt các định nghĩa từ một mô-đun python là PLY (Python-lex-yacc) http://www.dabeaz.com/ply/ - trong trường hợp đó các đối tượng chủ yếu là các đối tượng hàm, nhưng siêu dữ liệu từ các đối tượng hàm (tên của chúng, các docstrings và thứ tự của định nghĩa) cũng là một phần của đầu vào. Nó không phải là một ví dụ tốt cho việc sử dụng globals(). Ngoài ra, nó được nhập khẩu bởi 'cấu hình' - sau này là một tập lệnh python bình thường - chứ không phải là cách khác xung quanh.

Tôi đã sử dụng 'python khai báo' trên một số dự án mà tôi đã làm việc và đã có dịp sử dụng globals() khi viết cấu hình cho những người đó. Bạn chắc chắn có thể tranh luận rằng điều này là do một điểm yếu trong cách cấu hình 'ngôn ngữ' được thiết kế. Sử dụng globals() theo cách này không tạo ra kết quả rất rõ ràng; chỉ các kết quả có thể dễ duy trì hơn là viết ra hàng tá câu lệnh gần như giống hệt nhau.

Bạn cũng có thể sử dụng nó để cung cấp cho các biến có ý nghĩa trong tập tin cấu hình, theo tên của họ:

# All variables above here starting with Foo_k_ are collected 
# in Bar_klist 
# 
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')] 
Bar_klist = BarDef(foo_k , method = "kset") 

Phương pháp này có thể hữu ích cho bất kỳ mô-đun python định nghĩa rất nhiều bảng và các cấu trúc, để làm cho việc thêm các mục vào dữ liệu dễ dàng hơn, mà không phải duy trì các tham chiếu.

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