Python'da global kavramı

def islemler(x):
    global hesap
    hesap = x
    global sayı1
    sayı1 = float(giris.get())
    print(hesap)
    print(sayı1)
    giris.delete(0,'end')

burda tkinter ile hesap makinesi yapıyor kullanıcı ama global işleminin ne olduğunu anlamadım. neden kullanmış? Aslında işlemin tamamının açıklanmasına ihtiyacım var.

Fonksiyon içinde yerel (local) bir değişkene erişmek istenildiğinde global kullanılır.

Bu fonksiyon (islemler) parametre olarak aldığı değeri global hesap değişkenine eşitliyor.

giris.get()

ile entry’nin değerini alıp, float’a çeviriyor ve sayı1 değişkenine eşitliyor. Sonra iki değişkeni de ekrana yazdırıyor.
Son olarak

giris.delete(0,'end')

ile entry’nin içini temizliyor.

2 Beğeni

:\

Bir fonksiyon içerisinde o fonksiyona yerel (local) olmayan değişkenlere ulaşıp onları değiştirmek istediğimizde global kelimesini kullanıyoruz. Normalde fonksiyon içerisinde bir değişkene yalnız ulaşmak, onun değerini kullanmak istediğinizde (mesela print(hesap * 2)) ilk başta fonksiyondaki yerel değişkenlere bakılır. Yerel değişkenler: fonksiyon içerisinde degisken = ... formunda görülenler (veya benzeri; mesela for döngüsünün değişkeni gibi) ve fonksiyona parametre olarak gelen değişkenlerdir. Eğer Python aranan değişkeni (hesap) yerelde bulamazsa bir kapsam (scope) yukarı bakar. Sizde mesela fonksiyon 1-derinlikte olduğundan, üstteki scope global alana tekabül eder. Orada varsa hesap, değerini oradan alır ve işlemi gerçekleştirir. Orada da yoksa, başka üst bir scope kalmadığından, hata alırız. Bunu örnekleyelim:

hesap = 24

def fun(carpan):
    print(hesap * carpan)

fun(2)

carpan fonksiyona yereldir, paslanan değerini alır. hesap değildir; üst taraftan bakılır: vardır, o değeri alır. Ekranda 48 görürüz. global’e gerek yok zira hesap değişkeninin değerini okuyoruz sadece, üzerine yazıp onu değiştirmek gibi bir amacımız yok.

def fun(carpan):
    print(hesap * carpan)

fun(2)

Yine carpan fonksiyona yereldir, paslanan değerini alır. hesap yine değildir; üst taraftan bakılır: orada da yok; hata alırız (NameError: name ‘hesap’ is not defined).

Şimdi hesap değişkeninin değerini fonksiyon içerisinde değiştirmeye çalışalım.

hesap = 7

def fun(carpan):
    hesap = hesap + hesap * carpan

fun(0.5)

Hata aldık… UnboundLocalError: local variable ‘hesap’ referenced before assignment. Ne diyor?! Üstte bahsedildiği üzere, degisken = ... formu fonksiyon içerisinde görüldüğünde bu degisken fonksiyona yerel (local) olarak kaydedilir derleme zamanında. [Bunu şöyle görebiliriz:

# `fun` hemen üstteki fonksiyon
>>> import dis
>>> dis.dis(fun)
  2           0 LOAD_FAST                1 (hesap)
              2 LOAD_FAST                1 (hesap)
              4 LOAD_FAST                0 (carpan)
              6 BINARY_MULTIPLY
              8 BINARY_ADD
             10 STORE_FAST               1 (hesap)
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

Şimdi bu fonksiyonu “disassemble” ettik, dönüştürülen byte-code’lara bakıyoruz. LOAD_FAST’i “yerel değişkeni yükle” olarak düşünebiliriz. hesap (ve de carpan) yerel değişken olarak addediliyorlar.

Hemen ilk versiyona çevirip orada ne olduğuna bakalım:

>>> hesap  = 24
>>> def fun(carpan):
        print(hesap * carpan)

>>> dis.dis(fun)
  3           0 LOAD_GLOBAL              0 (print)
              2 LOAD_GLOBAL              1 (hesap)
              4 LOAD_FAST                0 (carpan)
              6 BINARY_MULTIPLY
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

hesap’a dikkat! LOAD_GLOBAL görüyoruz. Yerel olarak düşünülmedi, global kapsamdan alınacağı düşünülüyor. “Düşünülüyor” çünkü yerelde yok! Fonksiyon içerisindeki hesap değişkenini var olmayan bir değişken ismi yapın, mesela var_olmayan_degisken, yine aynı disassembly çıktısını alırsınız (aslında en baştan 2. kod örneğinde bunu yapıyoruz hesap’ı hiçbir yerde tanımlamadan). Değerin gerçekten var olup olmadığı çalışma zamanında (runtime) ortaya çıkacaktır.]

Neredeydik: UnboundLocalError: local variable ‘hesap’ referenced before assignment alıyoruz çalışma zamanında… Çünkü hesap yerel (local) olarak kaydedildi, ama runtime’da hesap = hesap + hesap * carpan satırında eşitliğin ilk olarak sağ tarafı "hesap"lanmaya (:d) çalışılır; ama gelin görün ki hesap değişkeninin değeri yok! Hataya şimdi hak veriyoruz: “yerel değişken hesap, hernagi bir assignment (değer atama) olmaksızın refere edilip kullanılmaya çalışıldı”. Burada, yukarıdaki, dışarıdaki niyetlenip değiştirmeye çalıştığımız hesap = 7 diye ilklendirdiğimiz o global hesap değişkeninin esamesi okunmuyor. O olmasa da aynı hatayı alırdık.

Bu hatadan kurtulmak ve niyetimiz olan dışarıdaki “asıl” hesap değişkenini değiştirmek adına Python’u yönlendirmeliyiz. Bunu da global direktifi ile yaparız:

hesap = 7

def fun(carpan):
    global hesap
    hesap = hesap + hesap * carpan

fun(0.5)

Burada diyoruz ki: hey Python, hesap = ... satırını görüp de bu hesap değişkeninin yerel olduğunu zannetme, ben senin aslında bunu global’den elde etmeni istiyorum. Bu sayede artık hesap yine global olarak addedilir (LOAD_GLOBAL), herhangi bir hata almayız, hesap değişkeninin değeri de yukarıdaki koddan sonra 1.5 katına çıkmış olur. Burada artık tek bir hesap var ortada, az önce hem yerel hem global vardı.

Velhasıl, global seviyeden (modül seviyesinden, herhangi bir fonksiyonun içerisinde olmayan seviyeden) bir değişkene yalnız ulaşmak ve değerini okumak (değiştirMEmek) istiyorsanız ne âlâ, global’e gerek yok. Ama yok, ulaşmakla kalmayıp değerini değiştirip üzerine yazmak istiyorsanız, global ile o değişkeni kastettiğinizi belirtmeniz gerekir; aksi takdirde (ümit ediyorum yukarıdakilere binaen) ya yeni, yerel bir değişken oluşturursunuz:

# Bu programda 2 farklı `hesap` değişkeni vardır. Biri fonksiyona yerel olandır,
# öteki ise global seviyede bulunandır. Bu yüzden 24\n7\n çıktısını alırız.
# Bu, siz kodunuzda `global hesap` yazmadığınızda olacak olandır.
hesap = 24

def fun():
    hesap = 7
    print(hesap)

fun()
print(hesap)

ya da hesap değişkenini eşitliğin sağ tarafında da kullanırsınız ve UnboundLocalError alırsınız (yukarılarda bahsettiğimiz).


Sonnot: global’in bir de nonlocal versiyonu vardır, o da fonksiyon-içinde-fonksiyonlardaki bu tür kargaşaları çözmek adına kullanılıyor. Bir de bu global’in gerekliliği mevzusu var: kısa olarak: global değişkenler yerine, değişkenlerin fonksiyona paslanıp geri döndürülmesi ve/veya obje-tabanlı programlamanın tercih edilmesi daha iyidir (bunun nedeni başka konularda olabilir). Ve fakat, Tkinter gibi bir modülün kullanımında global’ler az görülen bir şey değildir çünkü callback fonksiyonlarının döndürdüğünü event loop’un arasına girip alamıyoruz… Yine de *Var (StringVar, IntVar gibi) Tkinter’ın sizin için kolladığı ve widget’lara bağlanabilen değişkenler sayesinde ve/veya yine obje-tabanlılık yardımıyla duruma göre global’den kurtulmak pek tabii mümkündür biraz daha kod gerektirse de.

7 Beğeni

Fizikçi, matematikçi, kimyacı, jeolog ve antropologdan oluşan bir heyet bir araştırma için arazide bulunmaktadır. Birden yağmur bastırır. Hemen yakındaki bir arazi evine sığınırlar.

Ev sahibi onlara bir şeyler ikram etmek için biraz ayrılınca hepsinin dikkati soba üzerinde toplanır. Soba yerden 1 mt kadar yukarda, altındaki dizili taşların üzerindedir. Sobanın niçin böyle kurulmuş olabileceğine dair aralarında bir tartışma başlar.

Kimyacı, “Adam sobayı yükselterek aktivasyon enerjisini düşürmüş, böylece daha kolay yakmayı amaçlamış.” der.

Fizikçi, “Adam sobayı yükselterek konveksiyon yoluyla odanın daha kısa sürede ısınmasını sağlamak istemiş.” der.

Jeolog, “Burası tektonik hareketlilik bölgesi olduğundan herhangi bir deprem anında sobanin taşların üzerine yıkılmasını sağlayarak yangin olasılığını azaltmayı amaçlamış.” der.

Matematikçi, “Sobayı odanın geometrik merkezine kurmuş, böylece de odanın düzgün bir şekilde ısınmasını sağlamış.” der.

Antropolog, “Adam ilkel topluluklarda görülen ateşe tapmanın daha hafif biçimi olan ateşe saygı nedeniyle sobayı yukarıya kurmuş.” der.

Bu sırada ev sahibi içeri girer ve ona sobanın yukarda olmasının nedenini sorarlar.

Köylü cevap verir: “Boru yetmedi ağam!”

Elimizde bir kod parçası fal bakalım.

def islemler(x):
    global hesap
    hesap = x
    global sayı1
    sayı1 = float(giris.get())
    print(hesap)
    print(sayı1)
    giris.delete(0,'end

Tkinter ile hesap makinesi yapıyoruz, text ve label yerine print le sayı yazdırıyoruz.

Vardır bir hikmeti de kodun gerisi olmadan tahminden öteye geçmez.

@Dest basitçe açıklamış:

Yerel bir değişkene neden erişirsin, verisine ihtiyaç duyduğun için, yerel değişkenin değerini değiştirmek istese zaten fonksiyonun girişinde ulaşabiliyor. Ama aldığı x’in değerine erişmek isterse, global tanımlı bir değişken üzerinden erişebilecek.

python yorumlanan bir dil, bunlar da da sadece yorumlayıcı direktifi.

global etiketliyse, bu veriyi sadece fonksiyon sınırları içinde tanımlı kabul etme, fonksiyon dışında da tanınır kabul et, demekte.

Yani, gerçek derlenen bir dil olsa, bu bir global değişken olurdu, yerel değişkenlerle global değişkenler arasında ne fark var neden böyle?

Bilgisayar da sınırlı bir kaynağı olan sistem. Biz de bu kaynakları verimli kullanmaya özen gösteririz.

Global değişken dediğinizde neredeyse, programın başından sonuna kadar bellekte tutulur her an lazım olabilir diye.

Ama fonksiyonlar içindeki değişkenler, fonksiyon çalışıp bittikten sonra bir dahaki çağrıya kadar içindeki verileri tutmak zorunda değildir.

Bu nedenle zorunlu olmadıkça hiç bir veri global tanımlanmaz.

fonksiyona parametere olarak girip return ile dönüş değerini alarak işletilen bir program daha verimli olacaktır.

Yukarıdaki örnekte, x le zaten dışardan veri gelmiş, sonra bu veri hesap a neden aktarılmış?

Zaten geldiği yerdeki değişkende duruyordur o veri, bir de fonksiyon içinde global olarak tutmak neyin aklıdır anlamak için kodun tamamını görmek gerekir.

İlginç olan da şu, normal dillerde global veriler fonksiyonların dışında tanımlanır (zorunlu değil ama herkesin erişebileceği farkedilsin diye), fonksiyonlar tarafından da tanınır.

Ama python yorumlanan bir dil olduğunda tersten işleyip, fonksiyon içindne tanımlanıyor. Yani, sn @Dest in belirttiği gibi, fonksiyonun verisini dışarı çıkarabilmek için return yerine bir yol sunar. Tersi de olabilir, yani global veriyi yerele de aktarabilir ama kodun özelinde görünen bu.

Dediğim gibi kodun tamamını görmeden baca fıkrası oluyor.

Mesela giris() nedir?

Kodu görmüyoruz.

Bu kadar veriyle bu kadar açıklama yeter de artar bile.

Bundan fazlası, yurt dışına çıkmamış akademisyenin, python referansından okuduklarını öğrencinin kafasına vura vura öğretmeye çalıştığı gibi yavan kalır.

Öğretmek yerine ben biliyorum der gibi eğitmeye çalışmak sadece bizim ülkeye mahsus.

2 Beğeni

@anon18277073’in yukaridaki uzun aciklamali deneyinden bahsediyorsak, ben soyle bakiyorum:

Boyle cevaplar, yaziyi okuyan kadar (hatta cogu zaman, daha fazla) yazanin da ogrenmesini sagliyor. Kimisi biliyor ki cevabin bir yerinde bir hata veya belki yanlis bir varsayim yapilsa diger insanlar onu duzeltecek. (Yukarida @Dest’e oldugu gibi)

Bazen sorunun uzunlugu veya kalitesi, bazen soranin karakteri (bu soruyu ve yazarini tenzih ediyorum) boyle bir cevabi hak etmiyor. Bazen boyle cevaplar benim zannimda soruyu soranin ogrenimini aktif olarak baltaliyor. Mesela @Gok_Mavisi_Anka odev sorularini “pat” diye cevaplamayi cok seviyor. Illet oluyorum :​) Fakat daha once birine daha dedigim gibi, bu cevabin yazana veya herhangi bir baskasina zerre kadar faydasi varsa, sorunun veya soranin hak etmemesi onemli degil. Bazen ben de “odevimi benim icin yapin” sorularini olabilecek en absurt/kisa/degisik programlama paradigmali sekilde yanitliyorum. O zaman –ozellikle de benden daha “duzgun” bir cevap yazmis bir insani– nasil yargilayabilirim ki?

Yani aslinda (sanirim; ilk defa sonuca bagliyorum) forumu bir butun olarak ele almak lazim. Cevaplardan, yorumlardan, hatta sorulardan bile birden cok daha fazla kisi yararlanabiliyor. Zaten o yuzden surekli demiyor muyuz, “[mesaj atacagina] soru olarak sor, herkes gordun” diye?

5 Beğeni

Şahıslar, katılımcılar üzerinden gitmeyeyim sayın @aib.

Herkesin bir yoğurt yiyişi vardır.

Kimsenin tercihlerini cevaplama yöntemini sorgulamam.

Kendi bileceği iştir.

Ben olaya şöyle bakıyorum.

Önemli olan soruyu cevaplamak mıdır? Yoksa bu tür sorunlarla nasıl baş edebileceğini farkettirmek midir?

Benim tercihim, balık vermek yerine balık tutmayı anlatmak.

Yani “global” ne işe yarar diye soran birinin, python referansı okumayı ve oradan çözmesini önermek benim için tercihtir.

Bu nedenle girip bir referans linki atıp çıkacaktım mesaja.

Çünkü, her anahtar kelimeyi, her kod satırını bu nedir diye sormak zorunda kalacağına birinin nereye bakacağını göstermek daha mantıklı geliyor.

İkinci husus, bazı katılımcılar öğrenmek yerine işini hızlıca görmek ve gitmek ister, tabi ki bunlar sadece hazır koddan ibaret cevabını alıp çıkmayı isteyebilir.

Ama bu benim için çözüm değil.

Sizin dediğiniz gibi bazılar pat diye bir kod yapıştırıp çıkabiliyor, soran da bu kadarcıksa ihtiyacı kodu alıp gidiyor. Bu benim için iyi bir şey, bir şey öğrenmek mi istiyor yoksa bir parça işini görüp gitmek mi ayırabilmiş oluyorum.

Açıkcası bu kadar uzun yazmamın sebebi şuydu, dediğim gibi, bir link bırakıp çıkacaktım. Her satırını anlamadım diyen birine ne söylenebilir diye çok üstelemedim.

Ama bir açıklama var ve açıklamayı yapanın açıklaması bana yeterli geldi.

Hatta değinilmeyen bir açıdan açıklamayı yapana katkı sunmak istedim.

Diğer türlü, fonksiyona parametreyle mi veri geçilmiş, referansla mı geçilmiş, global mı tanımlamış return le neden dönmemiş kodu her yerini didiklerdim ama gerek görmedim.

Fıkra şundan,

Ortada bir parça kod var, bu kadarcık veriyle nereye çekersen oraya götürürsün.

İlk yorumcu da kısa öz neden kullandığını kendince ifade etmiş.

Hayır öyle değil böyle , hatta şöylede diyerek irdelenmesinin hevesini kıracağını düşünüyorum…

Mesela ben de şöyle mi yapsaydım.

#hesap = 7

def fun(carpan):
    global hesap
    hesap = 7
    hesap = hesap + hesap * carpan

fun(0.5)

hesap global olarak tanımladıktan sonra hesap oluşturulmuşsa dışarda tanımlı olmaksızın fonksiyon çağırıldığında artık global bir hesap değişkeni oluşur mu deseydim burun kıvırıp?

Sonra da kodu çalıştırıp, bak artık dışarda değişken tanımlı değil,

Öncesinde tanımlı olmasa dahi, fonksiyon çağırıldığında global olarak oluşturulyor falan mı deseydim.

Bence soruyu sorana bakmak lazım, sonrasında anlayabileceği ip uçları verip, anlamaya çalışmak lazım.

Ne kadar bildiğimiz değil ne kadar karşı tarafı anladığımızı önemsiyorum.

Adamı pataklar gibi cevaplamak benim tarzım değil.

Pataklayana da bir şey demem, ama biraz empati kurup, forumda cesaret gösterip iki satır bir şey yazanları hırpalamamak lazım.

Düzeltirken dahi, şöyle olmaz mı, şöyle de deneyelim mi demek benim bakış açım.

Bundan yurt dışına çıkmamış akademisyen tabiri kullandım.

Bizim tevhid-i tedrisatta döve döve öğrettiklerinden, döve döve öğretmeyi öğreniyorlar.

Azıcık farklı eğitim modellerini gören, biraz daha insancıl yaklaşıyor.

Python Variable Scope - Local, Global, Built-in, Enclosed - DataFlair (data-flair.training)

Hadi linki de vereyim.

Ahanda eksik, Built in scope a değinmemiş diye eleştirel yazmayı ben yakışsıksız buluyorum kendi yazılarımda.

Olay bundan ibaret.

Tabi sizin de bazan yazarken soranı patakladığınızı görmedim değil, bu da lazım birileri de pataklasın bazan şapşallaşıyorlar hakediyorlar demek ki diye çok üzerinde durmadım.

Ben de sonuç olarak şöyle söyleyim, benim açımdan ne kadar bildiğim yada ne kadar doğru ve kaliteli paylaşım yaptığım değil, karşımdakinin seviyesine ne kadar inebildiğim /çıkabildiğim ve onun ihtiyaçlarına ne kadar doğru cevap yazabildiğim önemli.

Kimi mavi hapı, kimi kırmızı kapı tercih ediyor. Ben kırmızı hapı tercih edenlere pembe bir dünya vaad etmiyorum.

Fıkra neden peki, Sınırlı mesajda sınırlı kodda ötesini berisini göremediğimiz zaman, adamın borusu kısa gelmiş yorumunu veremiyoruz.

Ben öncesinde tanımlı bir “hesap” değişkeni yoksa amacı şöyle yorumlardım;

Kodda global değişken çok yer kaplamasın diye fonksiyon ilk çağırılana kadar başka yerde tanımlamamış profesyonel bir yaklaşım ilginç derdim.

Yada daha önce tanımlanmış, profesyenel değil, returnle neden almamış diyebilirdim.

Yine sorduğum gibi, tkinter gibi görsel arayüz kullanırken print() kullandığını merak ederdim.

giris() fonksiyonunu merak ederdim.

Mümkünse kodun daha fazla kısmını görmek isterdim.

Böylece soba neden 1 metre yüksekte daha iyi tahminde bulunurdum.

Çünkü soruda şu var:

Yani bu cümleyi görüp de global anahtar kelimesini (keyword) örnekleyip gider miydim bilemedim.

Tabi bazı katılımcılar işinize gelirse bende böyle diyebilir.

İşte o durumda, soruyu soran da, cevaplanmaya çalışılan da, üzüm yemek yerine pataklanıyor gibi geliyor bana hepsi bu.

Tüm katılımcıları tenzih ederim.

Olabildiğince ön yargılı olmamak için cevaplara bakarken katılımcılara bakmaya çalışıyorum ki, olay şahsi gibi algılanmasın. Hep denk geliyorsa biraz da iğneyi kendimize batırmamız lazım.

Bir gün zıvanadan çıkar soru soranı pataklamaya kalkarsam beni tutun :slight_smile:

4 Beğeni

Ne pataklaması, ne hırpalaması yahu? Sayın Dest yazmış ki

Bu haliyle cümle yanlıştır / yanlış anlaşılmaya müsaittir. Fonksiyon içinde yerel değişkene ulaşmak için direkt değişkenin ismini kullanıyoruz. “Fonksiyon içindeki” yazsalardı daha doğrudur, düzeltilmesi gerekir. Ben de “:\” yazdım iki karakter. Şey mi yazdım, “ne alakası var arkadaş, o iş öyle değil, bilmiyorsan öğren de gel”? Yapmayın lütfen…

Sonrasında yazdıklarım da konu başlığına binaendi, sayın Dest’e değildi. Başlığın genelliğinden yararlanıp bir şeyler karaladım. Benim gibi yurt dışına çıkamamış akademisyen bozuntularının gönderilerini görmek istemiyorsanız ayarlardan yok sayıldı yapabilirsiniz benim profili :\.

3 Beğeni

Yani buradan," fonksiyon içinde bulunan bir veriye dışardan erişmekte global decoratörünü kullanabilirsin"i anlayamadın diye mi yanlış ve düzeltilmesi gerekli?

Gayet anlaşılır erişmek dediğinde dışardan çağrıştırıyor.

Yukarıda yazdığım mesajlar içinde " bozuntuları" yazan mesaj var mı?

Gereksiz agresif, gereksiz eleştirel, gereksiz gergin mesajlar.

Neden karaladığınzla ne yazdığınızla ilgili değil konu, paylaşım yaparken o yanlış bu doğru bu yanlış anlaşılır gibi düzeltmeleriniz sevimli görünmüyor.

Sevimli görünme derdiniz yoksa, alacağınız cevaplara da bozulmayacaksınız.

1 Beğeni