2012-05-14 51 views
176

Tôi biết tôi nên tránh sử dụng các biến toàn cầu ở nơi đầu tiên do nhầm lẫn như thế này, nhưng nếu tôi sử dụng chúng, đây là cách hợp lệ để sử dụng chúng? (Tôi cố gắng để gọi các bản sao toàn cầu của một biến được tạo ra trong một chức năng riêng biệt.)Các biến toàn cục chức năng Python?

x = somevalue 

def func_A(): 
    global x 
    # Do things to x 
    return x 

def func_B(): 
    x=func_A() 
    # Do things 
    return x 

func_A() 
func_B() 

Liệu các x rằng chức năng thứ hai sử dụng có cùng giá trị của bản sao chép toàn cầu của x rằng func_a sử dụng và sửa đổi? Khi gọi các hàm sau khi định nghĩa, có trật tự không?

+0

hãy cẩn thận cũng không giả sử chỉ vì bạn có một biến được gán trong hàm của bạn mà python sẽ xử lý các tham chiếu trước khi gán như vậy. Cho đến bài tập đầu tiên, nếu bạn sử dụng x, nó sẽ không phải là bài tập toàn cầu hoặc bài tập cục bộ. Bạn sẽ nhận được ngoại lệ UnboundLocalError khét tiếng trong khuôn mặt của bạn :) – osirisgothra

Trả lời

267

Nếu bạn chỉ muốn truy cập một biến toàn cục, bạn chỉ cần sử dụng tên của nó. Tuy nhiên, để thay đổi giá trị của nó, bạn cần phải sử dụng từ khóa global.

Ví dụ:

global someVar 
someVar = 55 

Điều này sẽ thay đổi giá trị của biến toàn cầu thành 55. Nếu không, nó sẽ chỉ gán 55 cho biến cục bộ.

Thứ tự của danh sách định nghĩa hàm không quan trọng (giả sử chúng không liên quan đến nhau theo một cách nào đó), thứ tự chúng được gọi.

+2

Trong đoạn mã mà tôi đưa ra, là func_B làm mọi thứ (1) với bản sao toàn cục của x (như nhận được từ func_A), (2) thành biến cục bộ x với cùng giá trị của kết quả của func_A, hoặc (3) với biến cục bộ x không có giá trị và (trong mắt của trình biên dịch) không có liên quan đến "một số giá trị" hoặc x trong func_A? –

+0

'x' trong' func_B' là biến cục bộ nhận giá trị của nó từ giá trị trả về của lệnh gọi đến 'func_A' - vì vậy tôi đoán điều đó sẽ biến nó thành (2) – Levon

+0

của bạn, giả sử x là một chuỗi ngẫu nhiên một số loại được tạo ra bởi func_A (tức là func_A tạo ra một x khác nhau mỗi khi nó được chạy.) Sẽ chạy chương trình như viết làm func_b sửa đổi một x khác với những gì ban đầu được tạo ra khi func_a được gọi? Nếu vậy, làm thế nào tôi có thể sửa chữa nó? –

0

Bạn phải sử dụng khai báo global khi bạn muốn thay đổi giá trị được gán cho biến toàn cầu.

Bạn không cần nó đọc từ biến toàn cầu. Lưu ý rằng việc gọi một phương thức trên một đối tượng (ngay cả khi nó thay đổi dữ liệu trong đối tượng đó) không làm thay đổi giá trị của biến giữ đối tượng đó (ma thuật phản xạ vắng mặt).

+2

Từ ngữ này là không may. Trong Python, giá trị được gán cho một biến là tham chiếu, vì vậy nó đúng về mặt kỹ thuật (và tôi không nghi ngờ gì bạn có ý đó), nhưng nhiều người đọc có thể giải thích "thay đổi giá trị" thành "biến đổi đối tượng", trường hợp - 'xs.append (xs.pop (0))' hoạt động tốt mà không có 'global xs'. – delnan

+0

@delnan Câu trả lời của tôi được diễn giải cẩn thận, nhưng tôi sẽ làm rõ. – Marcin

12

Như những người khác đã lưu ý, bạn cần khai báo biến số global trong hàm khi bạn muốn hàm đó có thể sửa đổi biến toàn cục. Nếu bạn chỉ muốn truy cập nó, thì bạn không cần global.

Để xem chi tiết hơn về điều đó, "sửa đổi" có nghĩa là gì: nếu bạn muốn liên kết lại tên chung để nó trỏ đến một đối tượng khác, tên phải được khai báo global trong chức năng.

Nhiều hoạt động mà thay đổi (đột biến) một đối tượng không lại gắn tên toàn cầu để trỏ đến một đối tượng khác nhau, và vì vậy họ tất cả hợp lệ mà không cần khai báo tên global trong hàm.

d = {} 
l = [] 
o = type("object", (object,), {})() 

def valid():  # these are all valid without declaring any names global! 
    d[0] = 1  # changes what's in d, but d still points to the same object 
    d[0] += 1  # ditto 
    d.clear()  # ditto! d is now empty but it`s still the same object! 
    l.append(0) # l is still the same list but has an additional member 
    o.test = 1 # creating new attribute on o, but o is still the same object 
65

Trong phạm vi Python, bất kỳ chuyển nhượng cho một biến chưa được công bố trong phạm vi đó tạo ra một biến địa phương mới trừ rằng biến được khai báo trước đó trong hàm như đề cập đến một biến scoped trên toàn cầu với từ khóa global .

Hãy nhìn vào một phiên bản sửa đổi của mã giả của bạn để xem những gì sẽ xảy ra:

# Here, we're creating a variable 'x', in the __main__ scope. 
x = 'None!' 

def func_A(): 
    # The below declaration lets the function know that we 
    # mean the global 'x' when we refer to that variable, not 
    # any local one 

    global x 
    x = 'A' 
    return x 

def func_B(): 
    # Here, we are somewhat mislead. We're actually involving two different 
    # variables named 'x'. One is local to func_B, the other is global. 

    # By calling func_A(), we do two things: we're reassigning the value 
    # of the GLOBAL x as part of func_A, and then taking that same value 
    # since it's returned by func_A, and assigning it to a LOCAL variable 
    # named 'x'.  
    x = func_A() # look at this as: x_local = func_A() 

    # Here, we're assigning the value of 'B' to the LOCAL x. 
    x = 'B' # look at this as: x_local = 'B' 

    return x # look at this as: return x_local 

Trong thực tế, bạn có thể viết lại tất cả các func_B với biến tên x_local và nó sẽ làm việc hệt.

Đơn đặt hàng chỉ quan trọng theo thứ tự các chức năng của bạn hoạt động thay đổi giá trị của toàn cầu x. Do đó, trong ví dụ của chúng tôi, đơn đặt hàng không quan trọng, kể từ func_B cuộc gọi func_A. Trong ví dụ này, đơn đặt hàng quan trọng:

def a(): 
    global foo 
    foo = 'A' 

def b(): 
    global foo 
    foo = 'B' 

b() 
a() 
print foo 
# prints 'A' because a() was the last function to modify 'foo'. 

Lưu ý rằng chỉ cần sửa đổi global để sửa đổi các đối tượng toàn cầu. Bạn vẫn có thể truy cập chúng từ bên trong một hàm mà không cần khai báo global. Như vậy, ta có:

x = 5 

def access_only(): 
    return x 
    # This returns whatever the global value of 'x' is 

def modify(): 
    global x 
    x = 'modified' 
    return x 
    # This function makes the global 'x' equal to 'modified', and then returns that value 

def create_locally(): 
    x = 'local!' 
    return x 
    # This function creates a new local variable named 'x', and sets it as 'local', 
    # and returns that. The global 'x' is untouched. 

Lưu ý sự khác biệt giữa create_locallyaccess_only-access_only đang truy cập vào x toàn cầu mặc dù không gọi global, và mặc dù create_locally không sử dụng global một trong hai, nó tạo ra một bản sao cục bộ từ đó là chỉ định một giá trị.

Sự nhầm lẫn ở đây là lý do tại sao bạn không nên sử dụng biến toàn cục.

+0

Tôi không nghĩ rằng điều này là rất khó hiểu trong thực tế, bạn chỉ cần hiểu [quy tắc phạm vi python] (http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules). – Darthfett

2

Dưới đây là một trường hợp đã phát hiện ra tôi, sử dụng giá trị toàn cầu làm giá trị mặc định của thông số.

globVar = None # initialize value of global variable 

def func(param = globVar): # use globVar as default value for param 
    print 'param =', param, 'globVar =', globVar # display values 

def test(): 
    global globVar 
    globVar = 42 # change value of global 
    func() 

test() 
========= 
output: param = None, globVar = 42 

Tôi đã dự kiến ​​tham số có giá trị là 42. Bất ngờ. Python 2.7 đã đánh giá giá trị của globVar khi nó phân tích cú pháp hàm func đầu tiên. Thay đổi giá trị của globVar không ảnh hưởng đến giá trị mặc định được gán cho param. Trì hoãn việc đánh giá, như sau, đã làm việc như tôi cần nó.

def func(param = eval('globVar')):  # this seems to work 
    print 'param =', param, 'globVar =', globVar # display values 

Hoặc, nếu bạn muốn được an toàn,

def func(param = None)): 
    if param == None: 
     param = globVar 
    print 'param =', param, 'globVar =', globVar # display values 
0

Bạn có thể trực tiếp truy cập vào một biến toàn cục bên trong một hàm. Nếu bạn muốn thay đổi giá trị của biến toàn cục đó, hãy sử dụng "global variable_name". Xem ví dụ sau:

var = 1 
def global_var_change(): 
     global var 
     var = "value changed" 
global_var_change() #call the function for changes 
print var 

Nói chung, đây không phải là thực hành lập trình tốt. Bằng cách phá vỡ logic không gian tên, mã có thể trở nên khó hiểu và gỡ rối.

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