การใช้ตัวแปรโกลบอลในฟังก์ชั่น


3113

ฉันจะสร้างหรือใช้ตัวแปรโกลบอลในฟังก์ชันได้อย่างไร

ถ้าฉันสร้างตัวแปรโกลบอลในฟังก์ชันหนึ่งฉันจะใช้ตัวแปรโกลบอลนั้นในฟังก์ชันอื่นได้อย่างไร ฉันต้องจัดเก็บตัวแปรโกลบอลในตัวแปรโลคัลของฟังก์ชันที่ต้องการเข้าถึงหรือไม่?

คำตอบ:


4245

คุณสามารถใช้ตัวแปรโกลบอลในฟังก์ชั่นอื่น ๆ โดยการประกาศดังเช่นglobalในแต่ละฟังก์ชั่นที่กำหนดให้:

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

ฉันจินตนาการเหตุผลว่าเป็นเพราะตัวแปรทั่วโลกอันตรายมาก Python ต้องการให้แน่ใจว่าคุณรู้จริง ๆ ว่านั่นคือสิ่งที่คุณกำลังเล่นด้วยโดยต้องการglobalคำหลักอย่างชัดเจน

ดูคำตอบอื่น ๆ หากคุณต้องการแชร์ตัวแปรโกลบอลข้ามโมดูล


838
มันพูดเกินจริงอย่างมากเมื่อพูดถึง globals ว่า "อันตรายมาก" Globals นั้นสมบูรณ์แบบในทุกภาษาที่มีอยู่และจะมีอยู่ตลอดไป พวกเขามีสถานที่ของพวกเขา สิ่งที่คุณควรพูดคือพวกเขาสามารถทำให้เกิดปัญหาได้หากคุณไม่มีเงื่อนงำในการเขียนโปรแกรม
แอนโธนี

207
ฉันคิดว่าพวกเขาค่อนข้างอันตราย อย่างไรก็ตามในไพ ธ อน "global" เป็นตัวแปรระดับโมดูลซึ่งแก้ปัญหาได้มากมาย
Fábio Santos

246
ฉันไม่เห็นด้วยกับเหตุผลที่ Python ต้องการglobalคำหลักก็เพราะ globals เป็นอันตราย แต่เป็นเพราะภาษาไม่ต้องการให้คุณประกาศตัวแปรอย่างชัดเจนและถือว่าตัวแปรที่คุณกำหนดนั้นมีขอบเขตฟังก์ชั่นโดยอัตโนมัติเว้นแต่คุณจะบอกเป็นอย่างอื่น globalคำหลักเป็นวิธีการที่ให้ไว้จะบอกว่ามันเป็นอย่างอื่น
Nate CK

7
@avgvstvs: และหากคุณกำลังใช้งานโปรแกรมเดียวกันโดยไม่มี globals คุณจะยังคงมีรหัสเส้นทางจำนวนเท่าเดิม การโต้เถียงที่คุณทำไม่ได้เกิดขึ้นกับกลม
Lightness Races ในวงโคจร

13
@LightnessRacesinOrbit ฉันไม่ได้รับคะแนนของคุณ หากคุณลบตัวแปรส่วนกลางคุณจะลบปัจจัยที่ซับซ้อนในตอนนี้ฟังก์ชั่นตามอำเภอใจไม่สามารถเปลี่ยนแปลงสถานะของโปรแกรมอีกต่อไปที่จุดต่าง ๆ ในการดำเนินการ - ดังนั้นการเปลี่ยนแปลงการดำเนินการในลักษณะที่ไม่สามารถใช้ได้กับฟังก์ชั่นอื่น ๆ คุณไม่ต้องติดตามอีกต่อไปว่า " f2()เปลี่ยนสถานะดังนั้นตอนนี้f3()อาจทำสิ่งที่ไม่คาดคิดตอนนี้ฟังก์ชั่นสามารถทำงานได้ไม่เชื่อเรื่องพระเจ้ากับสถานะโปรแกรมภายนอก
avgvstvs

775

ถ้าฉันเข้าใจสถานการณ์ของคุณอย่างถูกต้องสิ่งที่คุณเห็นคือผลลัพธ์ที่ Python จัดการกับเนมสเปซในพื้นที่ (ฟังก์ชัน) และโกลบอล (โมดูล)

สมมติว่าคุณมีโมดูลเช่นนี้:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

คุณอาจคาดหวังว่าสิ่งนี้จะพิมพ์ 42 แต่มันพิมพ์ 5 ตามที่ได้รับการกล่าวถึงถ้าคุณเพิ่มการglobalประกาศ '' ไปfunc1()แล้วfunc2()จะพิมพ์ 42

def func1():
    global myGlobal
    myGlobal = 42

สิ่งที่เกิดขึ้นในที่นี้คือ Python สันนิษฐานว่าชื่อใด ๆ ที่ได้รับมอบหมายในตำแหน่งใด ๆ ภายในฟังก์ชั่นนั้นเป็นของท้องถิ่นของฟังก์ชั่นนั้น หากเป็นเพียงการอ่านจากชื่อและไม่มีชื่ออยู่ภายในเครื่องจะพยายามค้นหาชื่อในขอบเขตที่มีอยู่ (เช่นขอบเขตทั่วโลกของโมดูล)

เมื่อคุณกำหนด 42 ให้กับชื่อmyGlobalดังนั้น Python จะสร้างตัวแปรท้องถิ่นที่จะเงาตัวแปรทั่วโลกในชื่อเดียวกัน โลคัลนั้นออกนอกขอบเขตและเก็บขยะเมื่อfunc1()ส่งคืน ในขณะเดียวกันfunc2()ไม่สามารถเห็นสิ่งอื่นใดนอกจากชื่อโกลบอล (ไม่แก้ไข) โปรดทราบว่าการตัดสินใจเนมสเปซนี้เกิดขึ้น ณ เวลารวบรวมไม่ใช่ในช่วงรันไทม์หากคุณต้องอ่านค่าmyGlobalด้านในfunc1()ก่อนที่คุณจะกำหนดคุณจะได้รับUnboundLocalErrorเนื่องจาก Python ได้ตัดสินใจแล้วว่ามันจะต้องเป็นตัวแปรในตัวเครื่อง ยังไม่ได้มีค่าใด ๆ ที่เกี่ยวข้อง แต่ด้วยการใช้globalคำสั่ง '' คุณจะบอก Python ว่าควรหาชื่ออื่นแทนการกำหนดไว้ในเครื่อง

(ฉันเชื่อว่าพฤติกรรมนี้เกิดขึ้นส่วนใหญ่ผ่านการเพิ่มประสิทธิภาพของเนมสเปซในพื้นที่ - หากไม่มีพฤติกรรมนี้ VM ของ Python จะต้องดำเนินการค้นหาชื่ออย่างน้อยสามครั้งในแต่ละครั้งที่มีการกำหนดชื่อใหม่ให้ภายในฟังก์ชัน (เพื่อให้แน่ใจว่า มีอยู่แล้วที่ระดับโมดูล / builtin) ซึ่งจะทำให้การทำงานทั่วไปเป็นไปอย่างช้าๆ)


คุณบอกว่าการตัดสินใจ namespace เกิดขึ้นในเวลารวบรวมฉันไม่คิดว่ามันจะเป็นจริง จากสิ่งที่ฉันได้เรียนรู้การรวบรวม python เพียงตรวจสอบข้อผิดพลาดทางไวยากรณ์ไม่ใช่ข้อผิดพลาดชื่อลองตัวอย่างนี้def A (): x + = 1หากคุณไม่ได้ใช้มันจะไม่ให้ UnboundLocalErrorกรุณายืนยันขอบคุณ
watashiSHUN

1
เป็นเรื่องปกติที่จะใช้ตัวพิมพ์ใหญ่สำหรับตัวแปรทั่วโลกเช่นMyGlobal = 5
Vassilis

3
@watashiSHUN: การตัดสินใจ namespace ไม่เกิดขึ้นที่รวบรวมเวลา การตัดสินใจว่าxเป็นโลคัลแตกต่างจากการตรวจสอบที่รันไทม์หากชื่อโลคัลถูกผูกไว้กับค่าก่อนที่จะถูกใช้ในครั้งแรก
BlackJack

9
@Vassilis: มันเป็นเรื่องธรรมดาที่จะกรณีบนทุกMY_GLOBAL = 5ตัวอักษร: ดูคู่มือสไตล์สำหรับงูหลามรหัส
BlackJack

223

คุณอาจต้องการที่จะสำรวจความคิดของnamespaces ใน Python โมดูลเป็นที่นิยมสำหรับข้อมูลทั่วโลก :

แต่ละโมดูลมีตารางสัญลักษณ์ส่วนตัวซึ่งใช้เป็นตารางสัญลักษณ์ทั่วโลกโดยฟังก์ชั่นทั้งหมดที่กำหนดไว้ในโมดูล ดังนั้นผู้เขียนของโมดูลสามารถใช้ตัวแปรทั่วโลกในโมดูลโดยไม่ต้องกังวลเกี่ยวกับการปะทะโดยไม่ตั้งใจกับตัวแปรทั่วโลกของผู้ใช้ modname.itemnameในทางตรงกันข้ามถ้าคุณรู้ว่าสิ่งที่คุณทำคุณสามารถสัมผัสตัวแปรทั่วโลกโมดูลที่มีสัญกรณ์เดียวกับที่ใช้ในการอ้างถึงฟังก์ชั่นของมัน

การใช้งาน Global-in-a-module เฉพาะอธิบายไว้ที่นี่ - ฉันจะแชร์ตัวแปรทั่วทั้งโมดูลได้อย่างไร และเพื่อความสมบูรณ์ของเนื้อหาจะถูกแชร์ที่นี่:

วิธีมาตรฐานของการแบ่งปันข้อมูลระหว่างโมดูลภายในโปรแกรมเดียวคือการสร้างโมดูลการกำหนดค่าพิเศษ (มักเรียกว่าconfigหรือcfg ) เพียงนำเข้าโมดูลการกำหนดค่าในทุกโมดูลของแอปพลิเคชันของคุณ โมดูลนั้นพร้อมใช้งานเป็นชื่อส่วนกลาง เนื่องจากมีเพียงหนึ่งอินสแตนซ์ของแต่ละโมดูลการเปลี่ยนแปลงใด ๆ ที่ทำกับวัตถุโมดูลจะถูกสะท้อนทุกที่ ตัวอย่างเช่น:

ไฟล์: config.py

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

ไฟล์: mod.py

import config
config.x = 1

ไฟล์: main.py

import config
import mod
print config.x

1
ด้วยเหตุผลที่ฉันไม่ชอบconfig.x ฉันสามารถกำจัดมันได้หรือไม่ ฉันมาด้วยx = lambda: config.xแล้วฉันมีค่าใหม่x()มา ด้วยเหตุผลบางอย่างการa = config.xไม่มีเคล็ดลับสำหรับฉัน
vladosaurus

3
@ vladosaurus from config import xแก้ปัญหานั้นได้ไหม?
jhylands

93

Python ใช้ฮิวริสติกแบบง่ายในการตัดสินใจว่าควรโหลดขอบเขตใดจากตัวแปรระหว่างท้องถิ่นและทั่วโลก หากชื่อตัวแปรปรากฏขึ้นทางด้านซ้ายมือของการมอบหมาย แต่ไม่ได้ประกาศเป็นโกลบอลจะถือว่าเป็นชื่อโลคัล หากไม่ปรากฏที่ด้านซ้ายมือของการมอบหมายจะถือว่าเป็นทั่วโลก

>>> 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        
>>> 

มาดูกันว่า baz ซึ่งปรากฏทางด้านซ้ายของการมอบหมายfoo()เป็นLOAD_FASTตัวแปรเดียว


12
ลักษณะการแก้ปัญหาสำหรับการดำเนินงานที่มีผลผูกพัน การมอบหมายเป็นหนึ่งในการดำเนินการดังกล่าวการนำเข้าอีกครั้ง แต่เป้าหมายของforลูปและชื่อหลังจากasในwithและexceptคำสั่งก็ถูกผูกไว้ด้วย
Martijn Pieters

@MartijnPieters สำหรับชื่อหลังจากasในexceptประโยคนี้ไม่ชัดเจนสำหรับฉัน แต่จะถูกลบอัตโนมัติเพื่อบันทึกหน่วยความจำ
Robert

1
@ Robert: ไม่บันทึกหน่วยความจำ แต่เพื่อหลีกเลี่ยงการสร้างการอ้างอิงแบบวงกลมซึ่งสามารถนำไปสู่การรั่วไหลของหน่วยความจำ นั่นเป็นเพราะข้อยกเว้นอ้างถึงการติดตามย้อนกลับและการสืบค้นกลับอ้างอิงทุกเนมสเปซในพื้นที่และทั่วโลกตามสแต็กการโทรทั้งหมดรวมถึงas ...เป้าหมายในตัวจัดการข้อยกเว้น
Martijn Pieters

62

หากคุณต้องการอ้างถึงตัวแปรกลางในฟังก์ชั่นคุณสามารถใช้คำหลักทั่วโลกเพื่อประกาศตัวแปรที่เป็นสากล คุณไม่จำเป็นต้องใช้มันในทุกกรณี (ในฐานะคนที่อ้างสิทธิ์ไม่ถูกต้อง) - หากไม่พบชื่อที่อ้างอิงในนิพจน์ในขอบเขตหรือขอบเขตในฟังก์ชันที่ฟังก์ชันนี้ถูกกำหนดมันจะถูกค้นหาในระดับสากล ตัวแปร

อย่างไรก็ตามหากคุณกำหนดให้กับตัวแปรใหม่ที่ไม่ได้ประกาศเป็นโกลบอลในฟังก์ชั่นมันจะถูกประกาศโดยปริยายว่าเป็นโลคัลและสามารถบดบังตัวแปรโกลบอลที่มีอยู่ด้วยชื่อเดียวกัน

นอกจากนี้ตัวแปรทั่วโลกยังมีประโยชน์ตรงกันข้ามกับความกระตือรือร้นของ OOP บางคนที่อ้างว่าเป็นอย่างอื่น - โดยเฉพาะอย่างยิ่งสำหรับสคริปต์ขนาดเล็กที่ OOP มีทักษะมากเกินไป


แน่นอนอีกครั้ง หัวรุนแรง ผู้ใช้ Python ส่วนใหญ่ใช้สำหรับการเขียนสคริปต์และสร้างฟังก์ชั่นเล็ก ๆ น้อย ๆ เพื่อแยกรหัสบิตขนาดเล็กออก
Paul Uszak

51

ถ้าฉันสร้างตัวแปรส่วนกลางในฟังก์ชันหนึ่งฉันจะใช้ตัวแปรนั้นในอีกฟังก์ชันหนึ่งได้อย่างไร

เราสามารถสร้างโลกด้วยฟังก์ชั่นต่อไปนี้:

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' 

การเขียนฟังก์ชั่นไม่ได้ใช้รหัสจริง ดังนั้นเราจึงเรียกcreate_global_variableฟังก์ชัน:

>>> create_global_variable()

ใช้ globals โดยไม่มีการดัดแปลง

คุณสามารถใช้มันได้ตราบใดที่คุณไม่คาดว่าจะเปลี่ยนวัตถุที่ชี้ไปที่:

ตัวอย่างเช่น,

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

และตอนนี้เราสามารถใช้ตัวแปรโกลบอล:

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

การแก้ไขตัวแปรโกลบอลจากภายในฟังก์ชัน

ในการชี้ตัวแปรทั่วโลกไปที่วัตถุอื่นคุณจะต้องใช้คำหลักทั่วโลกอีกครั้ง:

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

โปรดทราบว่าหลังจากเขียนฟังก์ชั่นนี้แล้วโค้ดที่เปลี่ยนแปลงก็ยังไม่ได้ทำงาน:

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

ดังนั้นหลังจากเรียกใช้ฟังก์ชัน:

>>> change_global_variable()

เราจะเห็นว่าตัวแปรทั่วโลกมีการเปลี่ยนแปลง global_variableชื่อในขณะนี้ชี้ไปที่'Bar':

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

โปรดทราบว่า "global" ใน Python ไม่ใช่ global อย่างแท้จริง - เป็น global เพียงระดับโมดูล ดังนั้นมันจึงใช้ได้เฉพาะกับฟังก์ชั่นที่เขียนในโมดูลที่เป็นแบบโกลบอลเท่านั้น ฟังก์ชั่นจำโมดูลที่พวกเขาเขียนดังนั้นเมื่อพวกเขาถูกส่งออกไปยังโมดูลอื่น ๆ พวกเขายังคงดูในโมดูลที่พวกเขาถูกสร้างขึ้นเพื่อค้นหาตัวแปรทั่วโลก

ตัวแปรโลคัลที่มีชื่อเดียวกัน

หากคุณสร้างตัวแปรท้องถิ่นด้วยชื่อเดียวกันมันจะบดบังตัวแปรทั่วโลก:

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!!!'

แต่การใช้ตัวแปรโลคอลผิดที่ไม่ได้เปลี่ยนตัวแปรโกลบอล:

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

โปรดทราบว่าคุณควรหลีกเลี่ยงการใช้ตัวแปรท้องที่ที่มีชื่อเดียวกันกับกลมหากคุณไม่ทราบว่าคุณกำลังทำอะไรและมีเหตุผลที่ดีในการทำเช่นนั้น ฉันยังไม่พบเหตุผลดังกล่าว

เราได้รับพฤติกรรมเดียวกันในชั้นเรียน

ติดตามความคิดเห็นถาม:

จะทำอย่างไรถ้าฉันต้องการสร้างตัวแปรส่วนกลางภายในฟังก์ชันภายในคลาสและต้องการใช้ตัวแปรนั้นภายในฟังก์ชันอื่นภายในคลาสอื่น?

ที่นี่ฉันแสดงให้เห็นว่าเราได้รับพฤติกรรมเดียวกันในวิธีการที่เราทำในฟังก์ชั่นปกติ:

class Foo:
    def foo(self):
        global global_variable
        global_variable = 'Foo'

class Bar:
    def bar(self):
        return global_variable + '!!!'

Foo().foo()

และตอนนี้:

>>> Bar().bar()
'Foo!!!'

แต่ฉันขอแนะนำให้แทนที่จะใช้ตัวแปรโกลบอลที่คุณใช้คุณลักษณะคลาสเพื่อหลีกเลี่ยงความยุ่งเหยิงในเนมสเปซของโมดูล นอกจากนี้โปรดทราบว่าเราไม่ได้ใช้selfอาร์กิวเมนต์ที่นี่ - เหล่านี้อาจเป็นวิธีการเรียน (มีประโยชน์ถ้ากลายพันธุ์แอตทริบิวต์ชั้นเรียนจากclsอาร์กิวเมนต์ปกติ) หรือวิธีการคงที่ (ไม่selfหรือcls)


เยี่ยมยอด แต่จะทำอย่างไรถ้าฉันต้องการสร้างตัวแปรโกลบอลภายในฟังก์ชันภายในคลาสและต้องการใช้ตัวแปรนั้นภายในฟังก์ชันอื่นภายในคลาสอื่น?
ค่อนข้าง

2
@anonmanx ฉันไม่รู้ว่าทำไมคุณถึงติดอยู่มันเป็นพฤติกรรมแบบเดียวกันในวิธีเดียวกับฟังก์ชั่นปกติ แต่ฉันจะอัปเดตคำตอบของฉันด้วยคำพูดของคุณและโค้ดตัวอย่างบางส่วนตกลงไหม
Aaron Hall

1
@anonmanx เป็นไงบ้าง
Aaron Hall

โอเคเข้าใจแล้ว ดังนั้นฉันจะต้องเรียกใช้ฟังก์ชันนั้นอย่างชัดเจนเพื่อใช้ตัวแปรโกลบอลนั้น
anonmanx

47

นอกจากคำตอบที่มีอยู่แล้วและทำให้สับสนมากขึ้น:

ในหลามตัวแปรที่อ้างถึงเฉพาะภายในฟังก์ชั่นที่มี ทั่วโลกโดยปริยาย ถ้าตัวแปรมีการกำหนดค่าใหม่ได้ทุกที่ภายในร่างกายของฟังก์ชั่นก็ถือว่าเป็นท้องถิ่น หากตัวแปรได้รับการกำหนดค่าใหม่ภายในฟังก์ชั่นตัวแปรจะอยู่ในพื้นที่โดยปริยายและคุณต้องประกาศอย่างชัดเจนว่าเป็น 'ทั่วโลก'

แม้ว่าในตอนแรกจะค่อนข้างแปลกใจ แต่การพิจารณาสักครู่ก็อธิบายสิ่งนี้ ในอีกด้านหนึ่งการกำหนดให้ส่วนกลางสำหรับตัวแปรที่กำหนดให้แถบกับผลข้างเคียงที่ไม่ได้ตั้งใจ ในทางกลับกันหากจำเป็นต้องใช้ทั่วโลกสำหรับการอ้างอิงระดับโลกทั้งหมดคุณจะต้องใช้งานโกลบอลตลอดเวลา คุณจะต้องประกาศเป็นโกลบอลทุกการอ้างอิงถึงฟังก์ชั่นในตัวหรือส่วนประกอบของโมดูลที่นำเข้า ความยุ่งเหยิงนี้จะกำจัดประโยชน์ของการประกาศทั่วโลกสำหรับการระบุผลข้างเคียง

ที่มา: กฎสำหรับตัวแปรโลคอลและตัวแปรโกลบอลใน Python คืออะไร .


34

ด้วยการประมวลผลแบบขนานตัวแปรส่วนกลางอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิดหากคุณไม่เข้าใจว่าเกิดอะไรขึ้น นี่คือตัวอย่างของการใช้ตัวแปรโกลบอลภายในการประมวลผลหลายตัว เราสามารถเห็นได้อย่างชัดเจนว่าแต่ละกระบวนการทำงานกับสำเนาของตัวแปรเอง:

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))

เอาท์พุท:

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]

25

สิ่งที่คุณพูดคือใช้วิธีเช่นนี้

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

แต่วิธีที่ดีกว่าคือใช้ตัวแปรโกลบอลเช่นนี้

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

ทั้งสองให้ผลลัพธ์เดียวกัน


25

ตามที่ปรากฎคำตอบนั้นง่ายเสมอ

นี่คือโมดูลตัวอย่างขนาดเล็กที่มีวิธีง่ายๆในการแสดงในmainคำจำกัดความ:

def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper

นี่คือวิธีแสดงในmainนิยาม:

import TestPy

def main():
    atest  = TestPy
    atest.five(5,8)
    print(atest.isTheNumber())

if __name__ == '__main__':
    main()

รหัสง่าย ๆ นี้ใช้งานได้ดีและมันจะทำงาน ฉันหวังว่ามันจะช่วย


1
ขอบคุณฉันใหม่กับงูใหญ่ แต่รู้จาวานิดหน่อย สิ่งที่คุณพูดทำงานให้ฉัน และการเขียน <ENTER> ทั่วโลกภายในชั้นเรียน .. ดูเหมือนจะสมเหตุสมผลมากกว่าฉันในการเขียนฟังก์ชั่น 'global a' .. ฉันสังเกตว่าคุณไม่สามารถพูดได้ทั่วโลก a = 4
barlop

2
นี่อาจเป็นเคล็ดลับหลามที่เรียบง่าย แต่มีประโยชน์มากสำหรับฉัน ฉันชื่อโมดูลนี้global_varsและเริ่มต้นข้อมูลในinit_global_varsที่ถูกเรียกในสคริปต์เริ่มต้น จากนั้นฉันก็สร้างวิธีการเข้าถึงสำหรับแต่ละ var ทั่วโลกที่กำหนดไว้ ฉันหวังว่าฉันสามารถโหวตได้หลายครั้ง! ขอบคุณ Peter!
swdev

1
เกิดอะไรขึ้นถ้ามีตัวแปรทั่วโลกมากมายและฉันไม่ต้องการที่จะทำรายการพวกเขาทีละคนหลังจากคำสั่งทั่วโลก?
jtlz2

23

คุณจำเป็นต้องอ้างอิงตัวแปรส่วนกลางในทุกฟังก์ชั่นที่คุณต้องการใช้

ดังต่อไปนี้:

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]
"""

3
'ในทุกฟังก์ชั่นที่คุณต้องการใช้' ไม่ถูกต้องอย่างละเอียดควรใกล้ถึง: 'ในทุกฟังก์ชั่นที่คุณต้องการอัปเดต '
spazm

21

คุณไม่ได้เก็บโกลบอลไว้ในตัวแปรโลคอลเพียงแค่สร้างการอ้างอิงแบบโลคัลกับออบเจ็กต์เดียวกับที่การอ้างอิงแบบโกลบอลดั้งเดิมของคุณอ้างถึง จำไว้ว่าทุกอย่างในงูใหญ่นั้นเป็นชื่อที่อ้างถึงวัตถุและไม่มีอะไรถูกคัดลอกในการทำงานปกติ

หากคุณไม่จำเป็นต้องระบุอย่างชัดเจนว่าเมื่อใดที่ตัวระบุจะอ้างอิงไปยังส่วนกลางที่กำหนดไว้ล่วงหน้าคุณจะต้องระบุอย่างชัดเจนเมื่อตัวระบุเป็นตัวแปรท้องถิ่นใหม่แทน (ตัวอย่างเช่นคำสั่ง 'var' เห็นใน JavaScript) เนื่องจากตัวแปรท้องถิ่นนั้นพบได้ทั่วไปมากกว่าตัวแปรทั่วโลกในระบบที่จริงจังและไม่สำคัญระบบ Python จึงเหมาะสมกว่าในกรณีส่วนใหญ่

คุณอาจมีภาษาที่พยายามเดาโดยใช้ตัวแปรโกลบอลหากมีอยู่หรือสร้างตัวแปรโลคอลหากไม่มี อย่างไรก็ตามนั่นอาจเป็นข้อผิดพลาดได้ง่าย ตัวอย่างเช่นการอิมพอร์ตโมดูลอื่นอาจแนะนำตัวแปรโกลบอลโดยใช้ชื่อนั้นโดยไม่ได้ตั้งใจซึ่งเป็นการเปลี่ยนพฤติกรรมของโปรแกรมของคุณ




14

ติดตามและเพิ่มส่วนต่อใช้ไฟล์เพื่อเก็บตัวแปรโกลบอลทั้งหมดที่ประกาศไว้แบบโลคัลแล้วimport as:

ไฟล์initval.py :

Stocksin = 300
Prices = []

ไฟล์getstocks.py :

import initval as iv

def getmystocks(): 
    iv.Stocksin = getstockcount()


def getmycharts():
    for ic in range(iv.Stocksin):

1
ข้อดีของการย้ายตัวแปรกลางไปยังไฟล์อื่นคืออะไร? มันเป็นเพียงการรวมกลุ่มตัวแปรทั่วโลกในไฟล์เล็ก ๆ ? และทำไมต้องใช้คำสั่งimport ... as ...? ทำไมไม่เป็นเช่นนั้นimport ...?
olibre

1
อ่า ... ในที่สุดฉันก็เข้าใจถึงประโยชน์: ไม่จำเป็นต้องใช้คำหลักglobal:-) => +1 :-) โปรดแก้ไขคำตอบของคุณเพื่อชี้แจงการซักถามเหล่านี้ที่คนอื่น ๆ อาจมี Cheers
olibre

13

การเขียนไปยังองค์ประกอบที่ชัดเจนของอาร์เรย์ทั่วโลกนั้นไม่จำเป็นต้องมีการประกาศทั่วโลกแม้ว่าการเขียนถึง "wholesale" จะมีความต้องการดังกล่าว:

import numpy as np

hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])

def func1():
    global hostValue    # mandatory, else local.
    hostValue = 2.0

def func2():
    global hostValue    # mandatory, else UnboundLocalError.
    hostValue += 1.0

def func3():
    global hostArray    # mandatory, else local.
    hostArray = np.array([14., 15.])

def func4():            # no need for globals
    hostArray[0] = 123.4

def func5():            # no need for globals
    hostArray[1] += 1.0

def func6():            # no need for globals
    hostMatrix[1][1] = 12.

def func7():            # no need for globals
    hostMatrix[0][0] += 0.33

func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix

7

ฉันกำลังเพิ่มสิ่งนี้เนื่องจากฉันไม่ได้เห็นคำตอบอื่นใดและอาจเป็นประโยชน์สำหรับบางคนที่ต้องดิ้นรนกับสิ่งที่คล้ายกัน globals()ฟังก์ชันส่งกลับแน่นอนพจนานุกรมสัญลักษณ์ทั่วโลกที่คุณสามารถ "อย่างน่าอัศจรรย์" ข้อมูลให้พร้อมใช้งานสำหรับส่วนที่เหลือของรหัสของคุณ ตัวอย่างเช่น:

from pickle import load
def loaditem(name):
    with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
        globals()[name] = load(openfile)
    return True

และ

from pickle import dump
def dumpfile(name):
    with open(name+".dat", "wb") as outfile:
        dump(globals()[name], outfile)
    return True

จะให้คุณถ่ายโอนข้อมูล / โหลดตัวแปรจากและเข้าสู่ namespace ส่วนกลาง สะดวกสบายมากไม่ต้องวุ่นวายไม่ต้องยุ่งยาก ค่อนข้างแน่ใจว่าเป็น Python 3 เท่านั้น


3
globals()คืนค่า globals ที่มีในบริบทท้องถิ่นเสมอดังนั้นการกลายพันธุ์ที่นี่อาจไม่สะท้อนในโมดูลอื่น
Kiran Jonnalagadda

6

อ้างอิงคลาสเนมสเปซที่คุณต้องการให้การเปลี่ยนแปลงแสดงขึ้น

ในตัวอย่างนี้นักวิ่งใช้ค่าสูงสุดจากไฟล์กำหนดค่า ฉันต้องการให้การทดสอบของฉันเปลี่ยนค่าของmaxเมื่อนักวิ่งใช้มัน

หลัก / config.py

max = 15000

หลัก / runner.py

from main import config
def check_threads():
    return max < thread_count 

การทดสอบ / runner_test.py

from main import runner                # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
   def test_threads(self):
       runner.max = 0                  # <----- 2. set global 
       check_threads()

1

Globals ใช้ได้ - ยกเว้น Multiprocessing

Globals ที่เกี่ยวข้องกับการประมวลผลหลายตัวบนแพลตฟอร์ม / envrionments ที่แตกต่างกันเช่น Windows / Mac OS ในด้านหนึ่งและ Linux ในอีกด้านหนึ่งมีปัญหา

ฉันจะแสดงให้คุณเห็นด้วยตัวอย่างง่ายๆที่ชี้ให้เห็นปัญหาที่ฉันพบเมื่อไม่นานมานี้

หากคุณต้องการที่จะเข้าใจว่าทำไมสิ่งต่าง ๆ บน Windows / MacOs และ Linux คุณจำเป็นต้องรู้ว่ากลไกเริ่มต้นในการเริ่มกระบวนการใหม่ใน ...

  • Windows / MacOs คือ 'วางไข่'
  • Linux คือ 'fork'

การเริ่มต้นการจัดสรรหน่วยความจำแตกต่างกันในการเริ่มต้น ... (แต่ฉันไม่ได้เข้าไปที่นี่)

ลองมาดูปัญหา / ตัวอย่าง ...

import multiprocessing

counter = 0

def do(task_id):
    global counter
    counter +=1
    print(f'task {task_id}: counter = {counter}')

if __name__ == '__main__':

    pool = multiprocessing.Pool(processes=4)
    task_ids = list(range(4))
    pool.map(do, task_ids)

ของ windows

หากคุณเรียกใช้งานบน Windows (และฉันคิดว่าบน MacOS ด้วย) คุณจะได้ผลลัพธ์ต่อไปนี้ ...

task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4

ลินุกซ์

หากคุณใช้งานบน Linux คุณจะได้สิ่งต่อไปนี้แทน

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.