Câu hỏi Sử dụng các biến toàn cầu trong một hàm


Làm thế nào tôi có thể tạo hoặc sử dụng một biến toàn cục trong một hàm?

Nếu tôi tạo một biến toàn cầu trong một hàm, làm thế nào tôi có thể sử dụng biến toàn cầu đó trong một hàm khác? Tôi có cần phải lưu trữ biến toàn cục trong một biến cục bộ của hàm cần truy cập của nó không?


2478
2018-01-08 05:45


gốc




Các câu trả lời:


Bạn có thể sử dụng biến toàn cầu trong các hàm khác bằng cách khai báo nó global trong mỗi chức năng gán cho nó:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

Tôi tưởng tượng lý do là vì các biến toàn cục rất nguy hiểm, Python muốn đảm bảo rằng bạn thực sự biết đó là những gì bạn đang chơi bằng cách yêu cầu rõ ràng global từ khóa.

Xem các câu trả lời khác nếu bạn muốn chia sẻ một biến toàn cục trên các mô-đun.


3509
2018-01-08 08:39



Đó là cường điệu cực đoan để đề cập đến globals là "rất nguy hiểm." Globals là hoàn toàn tốt đẹp trong mọi ngôn ngữ đã từng tồn tại và sẽ tồn tại. Họ có chỗ đứng của họ. Điều bạn nên nói là chúng có thể gây ra vấn đề nếu bạn không biết cách lập trình. - Anthony
Tôi nghĩ chúng khá nguy hiểm. Tuy nhiên trong các biến "toàn cầu" python thực sự là mô-đun cấp, mà giải quyết rất nhiều vấn đề. - Fábio Santos
Tôi không đồng ý rằng lý do Python yêu cầu global từ khóa là vì hình cầu là nguy hiểm. Thay vào đó, đó là vì ngôn ngữ không yêu cầu bạn khai báo một cách rõ ràng các biến và tự động giả định rằng một biến mà bạn chỉ định có phạm vi chức năng trừ khi bạn nói nó theo cách khác. Các global từ khóa là phương tiện được cung cấp để cho nó biết cách khác. - Nate C-K
Biến toàn cầu là một mùi thiết kế, trong hầu hết mọi ngôn ngữ tôi đã sử dụng một cách chuyên nghiệp. Giả sử bạn có một hàm có ba boolean: Đó là 8 đường dẫn mã có thể kiểm tra. Nếu bạn có 3 hàm với cùng số lượng boolean args, đó là 24 đường dẫn mã có thể. Sau đó, thêm một biến toàn cục boolean, bây giờ bạn đang tìm kiếm 24 ^ 2 đường dẫn mã có thể bởi vì bạn phải tính đến thực tế là TẤT CẢ các hàm có khả năng thay đổi trạng thái của biến toàn cục đó. Đây là lý do tại sao các kỹ thuật lập trình chức năng đã trở nên phổ biến. - avgvstvs
@LightnessRacesinOrbit Tôi không nhận được quan điểm của bạn. Nếu bạn xóa một biến toàn cầu, bạn loại bỏ yếu tố phức tạp trong đó, chức năng tùy ý không còn có thể thay đổi trạng thái chương trình, tại các điểm khác nhau trong thực thi - do đó thay đổi thực hiện theo cách không thể nhận biết được với các hàm khác dựa vào biến đó. Bạn không còn phải theo dõi, "Đã làm f2() thay đổi trạng thái ngay bây giờ f3() có thể làm điều gì đó bất ngờ? Các hàm bây giờ có thể hoạt động bất khả tri với trạng thái chương trình bên ngoài. - avgvstvs


Nếu tôi hiểu được tình huống của bạn một cách chính xác, những gì bạn thấy là kết quả của cách Python xử lý các vùng tên (chức năng) cục bộ và toàn cục (mô-đun).

Giả sử bạn có một mô-đun như thế này:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Bạn có thể mong đợi điều này để in 42, nhưng thay vào đó nó in 5. Như đã được đề cập, nếu bạn thêm một 'global'tuyên bố func1(), sau đó func2() sẽ in 42.

def func1():
    global myGlobal
    myGlobal = 42

Điều đang xảy ra ở đây là Python giả định rằng bất kỳ tên nào phân công, bất cứ nơi nào trong một hàm, là cục bộ cho hàm đó trừ khi được nói cách khác một cách rõ ràng. Nếu nó chỉ đọc hiểu từ tên và tên không tồn tại cục bộ, tên sẽ cố tìm kiếm tên trong bất kỳ phạm vi nào có chứa (ví dụ: phạm vi toàn cầu của mô-đun).

Khi bạn gán 42 cho tên myGlobal, do đó, Python tạo một biến cục bộ làm đổ bóng biến toàn cục có cùng tên. Địa phương đó nằm ngoài phạm vi và là thu gom rác khi nào func1() trả về; trong khi đó, func2() không bao giờ có thể thấy bất kỳ điều gì khác ngoài tên toàn cầu (chưa được sửa đổi). Lưu ý rằng quyết định không gian tên này xảy ra vào thời gian biên dịch, không phải lúc chạy - nếu bạn đã đọc giá trị của myGlobal phía trong func1() trước khi bạn gán cho nó, bạn sẽ nhận được UnboundLocalError, bởi vì Python đã quyết định rằng nó phải là một biến cục bộ nhưng nó chưa có bất kỳ giá trị nào được liên kết với nó. Nhưng bằng cách sử dụng 'global'tuyên bố, bạn nói với Python rằng nó nên tìm nơi khác cho tên thay vì gán cho nó cục bộ.

(Tôi tin rằng hành vi này bắt nguồn từ việc tối ưu hóa các không gian tên cục bộ - không có hành vi này, VM của VM sẽ cần phải thực hiện ít nhất ba lần tra cứu tên mỗi khi tên mới được gán vào bên trong một hàm (để đảm bảo rằng tên đã không) t đã tồn tại ở cấp mô-đun / xây dựng), điều này sẽ làm chậm đáng kể hoạt động rất phổ biến.)


661
2018-01-08 09:19



Bạn đã đề cập rằng quyết định không gian tên sẽ xảy ra tại thời gian biên dịch, Tôi không nghĩ đó là sự thật. từ những gì tôi học được biên dịch của python chỉ kiểm tra lỗi cú pháp, không phải lỗi tên thử ví dụ này def A (): x + = 1, nếu bạn không chạy nó, nó sẽ không cho UnboundLocalError, vui lòng xác minh cảm ơn - watashiSHUN
Người ta thường sử dụng một chữ hoa cho các biến toàn cục như MyGlobal = 5 - Vassilis
@ watashiSHUN: Quyết định không gian tên làm xảy ra tại thời gian biên dịch. Quyết định rằng x là địa phương khác với việc kiểm tra trong thời gian chạy nếu tên địa phương bị ràng buộc với một giá trị trước khi nó được sử dụng lần đầu tiên. - BlackJack
@Vassilis: Điều thường xảy ra với chữ hoa tất cả các bức thư: MY_GLOBAL = 5. Xem Hướng dẫn kiểu cho mã Python. - BlackJack
@BlackJack, đúng vậy, đúng rồi! (Tôi đã quen với c) - Vassilis


Bạn có thể muốn khám phá khái niệm về không gian tên. Trong Python, mô-đun là nơi tự nhiên cho toàn cầu dữ liệu:

Mỗi mô-đun có bảng biểu tượng riêng của nó, được sử dụng làm bảng biểu tượng toàn cục theo tất cả các hàm được định nghĩa trong mô-đun. Do đó, tác giả của một mô-đun có thể sử dụng các biến toàn cầu trong mô-đun mà không phải lo lắng về các xung đột tình cờ với các biến toàn cục của người dùng. Mặt khác, nếu bạn biết bạn đang làm gì, bạn có thể chạm vào các biến toàn cầu của một mô-đun với cùng một ký hiệu được sử dụng để chỉ các hàm của nó, modname.itemname.

Việc sử dụng cụ thể mô-đun toàn cầu trong mô-đun được mô tả ở đây - làm thế nào-do-i-share-toàn cầu-biến-qua-mô-đunvà để hoàn chỉnh nội dung được chia sẻ tại đây:

Cách kinh điển để chia sẻ thông tin giữa các mô-đun trong một chương trình là tạo ra một mô-đun cấu hình đặc biệt (thường được gọi là config hoặc cfg). Chỉ cần nhập mô-đun cấu hình vào tất cả các mô-đun của ứng dụng của bạn; sau đó mô-đun sẽ trở thành có sẵn dưới dạng tên chung. Vì chỉ có một cá thể của mỗi mô-đun, mọi thay đổi được thực hiện cho đối tượng mô-đun được phản ánh ở mọi nơi. Ví dụ:

Tệp: config.py

x = 0   # Default value of the 'x' configuration setting

Tệp: mod.py

import config
config.x = 1

Tệp: main.py

import config
import mod
print config.x

175
2018-01-08 05:59



vì một lý do tôi không thích config.x  tôi có thể loại bỏ nó không? Tôi đến với x = lambda: config.x và sau đó tôi có Mới giá trị trong x(). vì một lý do nào đó, có a = config.x không làm điều này cho tôi. - vladosaurus


Python sử dụng một heuristic đơn giản để quyết định phạm vi nào cần tải một biến từ, giữa local và global. Nếu một tên biến xuất hiện ở phía bên tay trái của một nhiệm vụ, nhưng không được khai báo chung, nó được giả định là cục bộ. Nếu nó không xuất hiện ở phía bên trái của một nhiệm vụ, nó được giả định là toàn cầu.

>>> import dis
>>> def foo():
...     global bar
...     baz = 5
...     print bar
...     print baz
...     print quux
... 
>>> dis.disassemble(foo.func_code)
  3           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (baz)

  4           6 LOAD_GLOBAL              0 (bar)
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  5          11 LOAD_FAST                0 (baz)
             14 PRINT_ITEM          
             15 PRINT_NEWLINE       

  6          16 LOAD_GLOBAL              1 (quux)
             19 PRINT_ITEM          
             20 PRINT_NEWLINE       
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        
>>> 

Xem baz, xuất hiện ở phía bên trái của bài tập trong foo(), là duy nhất LOAD_FAST biến.


75
2017-07-12 12:35



Cái nhìn heuristic cho hoạt động ràng buộc. Nhiệm vụ là một hoạt động như vậy, nhập một hoạt động khác. Nhưng mục tiêu của một for vòng lặp và tên sau as trong with và except báo cáo cũng bị ràng buộc. - Martijn Pieters♦


Nếu bạn muốn tham chiếu đến biến toàn cục trong một hàm, bạn có thể sử dụng toàn cầu từ khóa để khai báo biến nào là toàn cục. Bạn không phải sử dụng nó trong mọi trường hợp (như một người nào đó ở đây không xác nhận quyền sở hữu) - nếu tên được tham chiếu trong một biểu thức không thể được tìm thấy trong phạm vi địa phương hoặc phạm vi trong các hàm mà hàm này được xác định, nó được tra cứu trong toàn cầu biến.

Tuy nhiên, nếu bạn gán cho một biến mới không được khai báo là toàn cục trong hàm, nó được khai báo ngầm định là cục bộ và nó có thể làm lu mờ bất kỳ biến toàn cục hiện có nào có cùng tên.

Ngoài ra, các biến toàn cục là hữu ích, trái ngược với một số zealot OOP, những người tuyên bố khác - đặc biệt là cho các kịch bản nhỏ hơn, nơi OOP là quá mức cần thiết.


48
2018-01-08 09:03





Ngoài các câu trả lời đã tồn tại và để làm cho điều này khó hiểu hơn:

Trong Python, các biến chỉ được tham chiếu bên trong một hàm    ngầm toàn cầu. Nếu biến được gán giá trị mới ở bất kỳ đâu   trong cơ thể của hàm, nó được cho là địa phương. Nếu biến   được gán giá trị mới bên trong hàm, biến là   hoàn toàn cục bộ và bạn cần tuyên bố rõ ràng là ‘toàn cầu’.

Mặc dù có chút ngạc nhiên lúc đầu, cân nhắc của một thời điểm giải thích   điều này. Một mặt, yêu cầu toàn cầu cho các biến được gán cung cấp một   thanh chống lại các tác dụng phụ không lường trước. Mặt khác, nếu toàn cầu là   cần thiết cho tất cả các tham chiếu toàn cầu, bạn sẽ sử dụng toàn cầu tất cả   thời gian. Bạn phải khai báo là toàn cầu mọi tham chiếu đến tích hợp   chức năng 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 việc khai báo toàn cầu để xác định   tác dụng phụ.

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


36
2017-07-04 10:23





Nếu tôi tạo một biến toàn cầu trong một hàm, làm thế nào tôi có thể sử dụng biến đó trong một hàm khác?

Chúng ta có thể tạo ra một global với hàm sau:

def create_global_variable():
    global global_variable # must declare it to be a global first
    # modifications are thus reflected on the module's global scope
    global_variable = 'Foo' 

Viết một hàm không thực sự chạy mã của nó. Vì vậy, chúng tôi gọi create_global_variable chức năng:

>>> create_global_variable()

Sử dụng globals mà không sửa đổi

Bạn chỉ có thể sử dụng nó, miễn là bạn không muốn thay đổi đối tượng mà nó trỏ đến:

Ví dụ,

def use_global_variable():
    return global_variable + '!!!'

và bây giờ chúng ta có thể sử dụng biến toàn cầu:

>>> use_global_variable()
'Foo!!!'

Sửa đổi biến toàn cầu từ bên trong một hàm

Để trỏ biến toàn cầu vào một đối tượng khác, bạn được yêu cầu sử dụng lại từ khóa toàn cầu:

def change_global_variable():
    global global_variable
    global_variable = 'Bar'

Lưu ý rằng sau khi viết hàm này, mã thực sự thay đổi nó vẫn chưa chạy:

>>> use_global_variable()
'Foo!!!'

Vì vậy, sau khi gọi hàm:

>>> change_global_variable()

chúng ta có thể thấy rằng biến toàn cục đã được thay đổi. Các global_variable tên hiện trỏ đến 'Bar':

>>> use_global_variable()
'Bar!!!'

Lưu ý rằng "toàn cầu" trong Python không thực sự toàn cầu - nó chỉ toàn cầu ở cấp mô-đun. Vì vậy, nó chỉ có sẵn cho các hàm được viết trong các mô-đun trong đó nó là toàn cục. Các hàm nhớ mô-đun mà chúng được viết, vì vậy khi chúng được xuất vào các mô-đun khác, chúng vẫn tìm trong mô đun mà chúng được tạo để tìm các biến toàn cục.

Các biến cục bộ có cùng tên

Nếu bạn tạo một biến cục bộ có cùng tên, nó sẽ làm lu mờ biến toàn cầu:

def use_local_with_same_name_as_global():
    # bad name for a local variable, though.
    global_variable = 'Baz' 
    return global_variable + '!!!'

>>> use_local_with_same_name_as_global()
'Baz!!!'

Nhưng việc sử dụng biến cục bộ sai tên đó không thay đổi biến toàn cầu:

>>> use_global_variable()
'Bar!!!'

Lưu ý rằng bạn nên tránh sử dụng các biến cục bộ có cùng tên như globals trừ khi bạn biết chính xác những gì bạn đang làm và có một lý do rất tốt để làm như vậy. Tôi chưa gặp phải một lý do như vậy.


31
2018-01-01 19:55





Với việc thực thi song song, các biến toàn cầu có thể gây ra các kết quả không mong muốn nếu bạn không hiểu điều gì đang xảy ra. Dưới đây là ví dụ về việc sử dụng biến toàn cầu trong quá trình đa xử lý. Chúng ta có thể thấy rõ rằng mỗi quá trình đều hoạt động với bản sao biến của chính nó:

import multiprocessing
import os
import random
import sys
import time

def worker(new_value):
    old_value = get_value()
    set_value(random.randint(1, 99))
    print('pid=[{pid}] '
          'old_value=[{old_value:2}] '
          'new_value=[{new_value:2}] '
          'get_value=[{get_value:2}]'.format(
          pid=str(os.getpid()),
          old_value=old_value,
          new_value=new_value,
          get_value=get_value()))

def get_value():
    global global_variable
    return global_variable

def set_value(new_value):
    global global_variable
    global_variable = new_value

global_variable = -1

print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after  set_value(), get_value() = [%s]' % get_value())

processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))

Đầu ra:

before set_value(), get_value() = [-1]
after  set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]

28
2017-10-03 05:41





Bạn cần tham chiếu biến toàn cục trong mọi hàm bạn muốn sử dụng.

Như sau:

var = "test"

def printGlobalText():
    global var #wWe are telling to explicitly use the global version
    var = "global from printGlobalText fun."
    print "var from printGlobalText: " + var

def printLocalText():
    #We are NOT telling to explicitly use the global version, so we are creating a local variable
    var = "local version from printLocalText fun"
    print "var from printLocalText: " + var

printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""

19
2017-12-20 12:45



'trong mọi chức năng bạn muốn sử dụng' là không chính xác một cách tinh tế, nên gần hơn: 'trong mọi chức năng mà bạn muốn cập nhật' - spazm