Fungsi variabel global Python?

272

Saya tahu saya harus menghindari menggunakan variabel global karena kebingungan seperti ini, tetapi jika saya menggunakannya, apakah mengikuti cara yang valid untuk menggunakannya? (Saya mencoba memanggil salinan global dari variabel yang dibuat dalam fungsi terpisah.)

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

Apakah xfungsi kedua yang digunakan memiliki nilai yang sama dari salinan global xyang func_amenggunakan dan memodifikasi? Saat memanggil fungsi setelah definisi, apakah urutan penting?

Akshat Shekhar
sumber
1
hati-hati juga untuk tidak menganggap hanya karena Anda memiliki variabel yang ditugaskan dalam fungsi Anda bahwa python akan memperlakukan referensi sebelum penugasan seperti itu. Sampai tugas pertama, jika Anda menggunakan x, itu tidak akan menjadi global, atau lokal. Anda akan mendapatkan pengecualian UnboundLocalError yang terkenal di wajah Anda :)
osirisgothra

Jawaban:

412

Jika Anda hanya ingin mengakses variabel global, Anda cukup menggunakan namanya. Namun untuk mengubah nilainya, Anda perlu menggunakan globalkata kunci.

Misalnya

global someVar
someVar = 55

Ini akan mengubah nilai variabel global menjadi 55. Kalau tidak, itu hanya akan menetapkan 55 ke variabel lokal.

Urutan daftar definisi fungsi tidak masalah (dengan asumsi mereka tidak merujuk satu sama lain dalam beberapa cara), urutan mereka dipanggil tidak.

Levon
sumber
2
Dalam kode yang saya berikan, adalah func_B melakukan hal-hal (1) ke salinan global x (seperti yang diperoleh dari func_A), (2) ke variabel lokal x dengan nilai yang sama dari hasil func_A, atau (3) untuk variabel lokal x tanpa nilai dan (di mata kompiler) tidak ada hubungannya dengan "nilai" atau x dalam func_A?
Akshat Shekhar
xin func_Badalah variabel lokal yang mendapatkan nilainya dari nilai pengembalian panggilan ke func_A- jadi saya kira itu akan menjadikannya sebagai Anda (2)
Levon
ok, katakanlah x adalah urutan acak dari beberapa jenis yang dihasilkan oleh func_A (yaitu func_A yang menghasilkan x berbeda setiap kali dijalankan.) Akan menjalankan program seperti yang tertulis membuat func_b memodifikasi x berbeda dari apa yang awalnya diproduksi ketika func_a adalah dipanggil? Jika demikian, bagaimana saya bisa memperbaikinya?
Akshat Shekhar
1
Ya, jika func_Amengubah variabel global selama setiap proses dan mengembalikannya func_Buntuk digunakan, maka func_Bakan bekerja dengan nilai yang diubah setiap kali. Saya tidak yakin tentang "cara memperbaikinya". Anda mungkin ingin menerima jawaban yang paling membantu untuk pertanyaan Anda saat ini / asli dan kemudian mempertimbangkan untuk membuka pertanyaan lain tentang apa yang tampak seperti pertanyaan tindak lanjut.
Levon
1
Sebenarnya itu tergantung apa x. Jika x tidak dapat diubah, maka x dalam func_B akan tetap di dalamnya, karena dideklarasikan secara lokal bahkan jika mereka memiliki nilai yang sama. Ini berlaku untuk tupel, ints ... Jika ini adalah contoh dari daftar misalnya dan Anda lakukan x.append("..."), itu adalah variabel global x yang diubah, karena yang lokal merujuk yang global.
jadkik94
111

Di dalam lingkup Python, setiap penugasan ke variabel yang belum dideklarasikan dalam lingkup itu menciptakan variabel lokal baru kecuali variabel itu dinyatakan sebelumnya dalam fungsi sebagai merujuk ke variabel cakupan global dengan kata kunci global.

Mari kita lihat pseudocode versi modifikasi untuk melihat apa yang terjadi:

# 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

Bahkan, Anda bisa menulis ulang semua func_Bdengan variabel bernama x_localdan itu akan berfungsi secara identik.

Urutan hanya penting sejauh urutan di mana fungsi Anda melakukan operasi yang mengubah nilai global x. Jadi dalam contoh kami, pesanan tidak masalah, karena func_Bpanggilan func_A. Dalam contoh ini, pesanan memang penting:

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

Perhatikan bahwa globalhanya diperlukan untuk memodifikasi objek global. Anda masih dapat mengaksesnya dari dalam suatu fungsi tanpa mendeklarasikan global. Jadi, kami memiliki:

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.

Perhatikan perbedaan antara create_locallydan access_only- access_onlymengakses global x meskipun tidak menelepon global, dan meskipun create_locallytidak menggunakan globalkeduanya, ia membuat salinan lokal karena ini memberikan nilai.

Kebingungan di sini adalah mengapa Anda tidak harus menggunakan variabel global.

jdotjdot
sumber
2
Saya tidak berpikir ini sangat membingungkan dalam prakteknya, Anda hanya harus memahami aturan pelingkupan python .
Casey Kuball
20

Seperti yang telah dicatat orang lain, Anda perlu mendeklarasikan variabel globaldalam suatu fungsi ketika Anda ingin fungsi itu dapat memodifikasi variabel global. Jika Anda hanya ingin mengaksesnya, maka Anda tidak perlu global.

Untuk sedikit lebih mendetail tentang hal itu, apa artinya "memodifikasi" adalah ini: jika Anda ingin mengikat kembali nama global sehingga menunjuk ke objek yang berbeda, nama harus dideklarasikan globaldalam fungsi.

Banyak operasi yang memodifikasi (bermutasi) suatu objek tidak mengikat kembali nama global untuk menunjuk ke objek yang berbeda, sehingga semuanya valid tanpa menyatakan nama globaldalam fungsi.

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
baik hati
sumber
8

Berikut adalah satu kasus yang menarik saya, menggunakan global sebagai nilai default dari suatu parameter.

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

Saya berharap param memiliki nilai 42. Kejutan. Python 2.7 mengevaluasi nilai globVar ketika pertama-tama menguraikan fungsi func. Mengubah nilai globVar tidak memengaruhi nilai default yang ditetapkan untuk param. Menunda evaluasi, seperti yang berikut ini, bekerja sesuai kebutuhan saya.

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

Atau, jika Anda ingin aman,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values
SoloPilot
sumber
Itu mengingatkan saya pada masalah menetapkan daftar kosong sebagai nilai default . Dan, seperti dalam contoh, gunakan isuntuk memeriksa apakah ada sesuatu None, bukan perbandingan normal ==.
berna1111
6

Anda dapat langsung mengakses variabel global di dalam suatu fungsi. Jika Anda ingin mengubah nilai variabel global itu, gunakan "global variable_name". Lihat contoh berikut:

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

Secara umum, ini bukan praktik pemrograman yang baik. Dengan memecah logika namespace, kode bisa menjadi sulit dipahami dan didebug.

Bising_Botnet
sumber
2

Anda harus menggunakan globaldeklarasi ketika Anda ingin mengubah nilai yang diberikan ke variabel global.

Anda tidak perlu membaca dari variabel global. Perhatikan bahwa memanggil metode pada objek (bahkan jika itu mengubah data di dalam objek itu) tidak mengubah nilai variabel yang menahan objek tersebut (absen sihir reflektif).

Marcin
sumber
2
Kata-kata ini sangat disayangkan. Dalam Python, nilai yang diberikan ke variabel adalah referensi, sehingga secara teknis benar (dan saya tidak ragu Anda maksudkan itu), tetapi banyak pembaca dapat menafsirkan "mengubah nilai" sebagai "mengubah objek", yang tidak kasus ini - xs.append(xs.pop(0))bekerja dengan baik tanpa global xs.
@delnan Jawaban saya ditulis dengan hati-hati, tetapi saya akan mengklarifikasi.
Marcin