Sử dụng từ khóa toàn cầu của Wikipedia trong Python


285

Điều tôi hiểu từ việc đọc tài liệu là Python có một không gian tên riêng cho các hàm và nếu tôi muốn sử dụng một biến toàn cục trong hàm đó, tôi cần sử dụng global.

Tôi đang sử dụng Python 2.7 và tôi đã thử bài kiểm tra nhỏ này

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

Có vẻ như mọi thứ đang hoạt động tốt ngay cả khi không có global. Tôi đã có thể truy cập biến toàn cầu mà không có bất kỳ vấn đề.

Tôi có thiếu thứ gì không? Ngoài ra, sau đây là từ tài liệu Python:

Các tên được liệt kê trong câu lệnh chung không được xác định là tham số chính thức hoặc trong mục tiêu điều khiển vòng lặp, định nghĩa lớp, định nghĩa hàm hoặc câu lệnh nhập.

Mặc dù các tham số chính thức và định nghĩa lớp có ý nghĩa với tôi, tôi không thể hiểu được giới hạn đối với mục tiêu điều khiển vòng lặp và định nghĩa hàm.


1
Tôi nghĩ rằng bạn đang nhầm lẫn với php yêu cầu sử dụng từ khóa toàn cầu - các tài liệu python xác nhận điều này - về cơ bản nếu nó không được xác định trong bối cảnh địa phương thì nó được coi là toàn cầu
tobyodavies

11
Hãy cẩn thận với từ ngữ của bạn: Python không có không gian tên riêng biệt cho các hàm (điều đó có nghĩa là bạn có thể có def foo(): ...foo = ...đồng thời). Nó tạo ra một phạm vi mới cho mỗi cuộc gọi chức năng. (Nhưng nó khác với mọi ngôn ngữ cấp cao từ xa khác trên thế giới như thế nào?)

Câu trả lời:


366

Từ khóa globalchỉ hữu ích để thay đổi hoặc tạo các biến toàn cục trong ngữ cảnh cục bộ, mặc dù việc tạo các biến toàn cục hiếm khi được coi là một giải pháp tốt.

def bob():
    me = "locally defined"    # Defined only in local context
    print(me)

bob()
print(me)     # Asking for a global variable

Ở trên sẽ cung cấp cho bạn:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print(me)
NameError: name 'me' is not defined

Trong khi nếu bạn sử dụng globalcâu lệnh, biến sẽ có sẵn "bên ngoài" phạm vi của hàm, thực sự trở thành một biến toàn cục.

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print(me)

bob()
print(me)     # Asking for a global variable

Vì vậy, đoạn mã trên sẽ cung cấp cho bạn:

locally defined
locally defined

Ngoài ra, do tính chất của python, bạn cũng có thể sử dụng globalđể khai báo các hàm, lớp hoặc các đối tượng khác trong ngữ cảnh cục bộ. Mặc dù tôi sẽ khuyên chống lại nó vì nó gây ra ác mộng nếu có sự cố hoặc cần gỡ lỗi.


59
"Toàn cầu" trong bối cảnh này dường như khác với các ngôn ngữ khác coi là "toàn cầu". Trong Python, một tham chiếu "toàn cầu" vẫn nằm trong giới hạn của mô-đun và sẽ cần được tham chiếu từ bên ngoài mô-đun đó dưới dạng "module.global_var" chứ không chỉ đơn giản là "global_var" như người ta mong đợi.
nước ép

17
@juice - Trong Python không có thứ gọi là globalstự động tuyệt đối được xác định trên tất cả các không gian tên (rất may). Như bạn đã chỉ ra một cách chính xác, toàn cầu được liên kết với một không gian tên trong một mô-đun, tuy nhiên nó có thể được nhập vào một mô-đun khác dưới dạng from module import variablehoặc import module.variable. Trong trường hợp đầu tiên, việc nhập sẽ làm cho biến có thể truy cập được variablemà không yêu cầu tham chiếu như module.. Nếu nó được coi là toàn cầu trong phạm vi của mô-đun sẽ phụ thuộc vào nơi nó được nhập. Cũng xem nonlocalnhư một từ khóa liên quan đến phạm vi mới trong python 3.
giải mã

3
Bạn có thể giải thích tại sao các biến toàn cầu không phải là một giải pháp tốt? Tôi thường nghe điều này, nhưng trong dự án hiện tại của tôi, họ dường như chỉ làm những gì tôi cần họ làm. Có điều gì độc ác hơn tôi chưa từng nghĩ đến?
Robin Newhouse

5
@RobinNewhouse Có một vài câu hỏi về SO đã đề cập đến chủ đề đó và các bài viết không phải SO khác .
giải mã

213

Mặc dù bạn có thể truy cập các biến toàn cục mà không cần globaltừ khóa, nhưng nếu bạn muốn sửa đổi chúng, bạn phải sử dụng globaltừ khóa. Ví dụ:

foo = 1
def test():
    foo = 2 # new local foo

def blub():
    global foo
    foo = 3 # changes the value of the global foo

Trong trường hợp của bạn, bạn chỉ cần truy cập vào danh sách sub.


3
Với một cảnh báo: foo = 3không có tác phẩm toàn cầu, nhưng foo được định nghĩa lại cục bộ trong blubphạm vi chức năng & không sửa đổi biến foo gốc. Điều này khá khó hiểu với tôi.
chhantyal

1
@chhantyal nếu bằng cách làm việc, bạn có nghĩa là nó không gây ra lỗi, bạn đúng, nhưng trong bối cảnh của Ivo Wetzel, nó sẽ không hoạt động như dự định. Có những cách sử dụng cho hành vi như vậy, nhưng nó thường không phải là những gì lập trình viên muốn.
dân chủ

77

Đây là sự khác biệt giữa việc truy cập tên và ràng buộc nó trong một phạm vi.

Nếu bạn chỉ tìm kiếm một biến để đọc giá trị của nó, bạn đã có quyền truy cập vào phạm vi toàn cầu cũng như cục bộ.

Tuy nhiên, nếu bạn gán cho một biến có tên không thuộc phạm vi cục bộ, bạn sẽ ràng buộc tên đó vào phạm vi này (và nếu tên đó cũng tồn tại dưới dạng toàn cầu, bạn sẽ ẩn tên đó).

Nếu bạn muốn có thể gán cho tên toàn cầu, bạn cần yêu cầu trình phân tích cú pháp sử dụng tên toàn cầu thay vì liên kết một tên địa phương mới - đó là những gì mà từ khóa 'toàn cầu' thực hiện.

Liên kết bất cứ nơi nào trong một khối làm cho tên ở mọi nơi trong khối đó bị ràng buộc, điều này có thể gây ra một số hậu quả trông khá kỳ lạ (ví dụ: UnboundLocalError đột nhiên xuất hiện trong mã làm việc trước đó).

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    r()
  File "<pyshell#32>", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 

rất phản trực giác, khó tin rằng đây là mã trăn hợp lệ
PlsWork

52

Các câu trả lời khác trả lời câu hỏi của bạn. Một điều quan trọng khác cần biết về tên trong Python là chúng là cục bộ hoặc toàn cầu trên cơ sở từng phạm vi.

Hãy xem xét điều này, ví dụ:

value = 42

def doit():
    print value
    value = 0

doit()
print value

Bạn có thể đoán rằng value = 0câu lệnh sẽ được gán cho một biến cục bộ và không ảnh hưởng đến giá trị của cùng một biến được khai báo bên ngoài doit()hàm. Bạn có thể ngạc nhiên hơn khi phát hiện ra rằng đoạn mã trên sẽ không chạy. Câu lệnh print valuebên trong hàm tạo ra mộtUnboundLocalError.

Lý do là Python đã nhận thấy rằng, ở nơi khác trong hàm, bạn gán tên valuevà cũng valuekhông được khai báo global. Điều đó làm cho nó một biến cục bộ. Nhưng khi bạn cố in nó, tên địa phương chưa được xác định. Python trong trường hợp này không quay trở lại tìm kiếm tên như một biến toàn cục, như một số ngôn ngữ khác làm. Về cơ bản, bạn không thể truy cập một biến toàn cục nếu bạn đã xác định một biến cục bộ có cùng tên ở bất kỳ đâu trong hàm.


1
Cảm ơn đã chỉ ra điều này. Vì vậy, miễn là phạm vi cục bộ của bạn không gán cho tên tồn tại bên ngoài tên đó, thì các tham chiếu trong phạm vi cục bộ sẽ sử dụng tên bên ngoài. Tuy nhiên, nếu bất cứ nơi nào trong chức năng của bạn, bạn gán cho tên đó, các tham chiếu trong phạm vi cục bộ đó, ngay cả trước khi gán cục bộ, không nhìn ra bên ngoài.
Dmitry Minkovsky

1
Chính xác, bạn đã có nó. global(hoặc nonlocaltrong Python 3.x) ghi đè hành vi này và cho phép bạn gán lại tên bên ngoài.
loại

2
Trong các ngôn ngữ khác, điều này dường như được gọi là "cẩu", ví dụ như thế này: github.com/sh
Xuyên/javascript-potypes/blob/master/iêu

Để thêm sự xúc phạm đến thương tích, biến khai báo với JavaScript mới hơn từ khóa letđược không kéo lên.
loại

Là nhanh hơn để truy cập một biến toàn cầu được khai báo với globalhoặc nó không quan trọng?
mato

14

Truy cập một tên và gán tên là khác nhau. Trong trường hợp của bạn, bạn chỉ cần truy cập vào một tên.

Nếu bạn gán cho một biến trong một hàm, biến đó được coi là cục bộ trừ khi bạn khai báo nó là toàn cục. Trong trường hợp không có điều đó, nó được coi là toàn cầu.

>>> x = 1         # global 
>>> def foo():
        print x       # accessing it, it is global

>>> foo()
1
>>> def foo():   
        x = 2        # local x
        print x 

>>> x            # global x
1
>>> foo()        # prints local x
2

7
  • Bạn có thể truy cập các từ khóa toàn cầu mà không cần từ khóa global
  • Để có thể sửa đổi chúng, bạn cần nói rõ rằng từ khóa là toàn cầu. Nếu không, từ khóa sẽ được khai báo trong phạm vi địa phương.

Thí dụ:

words = [...] 

def contains (word): 
    global words             # <- not really needed
    return (word in words) 

def add (word): 
    global words             # must specify that we're working with a global keyword
    if word not in words: 
        words += [word]

2

Bất kỳ biến nào được khai báo bên ngoài hàm đều được coi là toàn cục, chỉ khi khai báo chúng từ bên trong hàm (trừ hàm tạo) mà bạn phải xác định rằng biến đó là toàn cục.


1

Điều này được giải thích tốt trong Câu hỏi thường gặp về Python

Các quy tắc cho các biến cục bộ và toàn cầu trong Python là gì?

Trong Python, các biến chỉ được tham chiếu bên trong một hàm là toàn cục. Nếu một biến được gán một giá trị ở bất kỳ đâu trong thân hàm, thì nó được coi là cục bộ trừ khi được khai báo rõ ràng là toàn cục.

Mặc dù có một chút ngạc nhiên lúc đầu, sự cân nhắc của một khoảnh khắc giải thích điều này. Một mặt, yêu cầu globalcho các biến được chỉ định cung cấp một thanh chống lại các tác dụng phụ ngoài ý muốn. Mặt khác, nếu globalđược yêu cầu cho tất cả các tài liệu tham khảo toàn cầu, bạn sẽ sử dụng globalmọi lúc. Bạn phải khai báo như globalmọi tham chiếu đến hàm tích hợp hoặc thành phần của mô-đun đã nhập. Sự lộn xộn này sẽ đánh bại tính hữu ích của globaltuyên bố để xác định các tác dụng phụ.

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python


0

Điều đó có nghĩa là bạn không nên làm như sau:

x = 1

def myfunc():
  global x

  # formal parameter
  def localfunction(x):
    return x+1

  # import statement
  import os.path as x

  # for loop control target
  for x in range(10):
    print x

  # class definition
  class x(object):
    def __init__(self):
      pass

  #function definition
  def x():
    print "I'm bad"

ikostia được liệt kê tất cả những thứ mà bạn không thể sử dụng 'x' vì đã sử dụng toàn cầu - docs.python.org/reference/...
pycruft

1
@ Unode: Tôi chỉ đưa ra tất cả các trường hợp mà NikhilRathod đã đưa ra trong trích dẫn của mình.
ikostia

0

Toàn cầu làm cho biến "Toàn cầu"

def out():
    global x
    x = 1
    print(x)
    return


out()

print (x)

Điều này làm cho 'x' hoạt động như một biến bình thường bên ngoài hàm. Nếu bạn lấy toàn cầu ra thì nó sẽ báo lỗi vì nó không thể in một biến bên trong hàm.

def out():
     # Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
    x = 1
    print(x)
    return


out()

print (x)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.