Python'daki En Tuhaf Satır — Esrarı Çözüldü
Neredeyse herhangi bir Python dosyasını aç; eninde sonunda en altında bunu görürsün:
if __name__ == "__main__":
main()
Sihirli gibi görünen bir boilerplate. Aslında ne yaptığını bilince çok pratik bir özellik — ve Python "script"ler ile "kütüphaneler" arasına bir sınır çizmediği için var.
Durum: Bir Dosyayı Kullanmanın İki Yolu
Python'daki her .py dosyası iki farklı şekilde kullanılabilir:
- Script olarak — doğrudan
python3 file.pyile çalıştırırsın. - Modül olarak — başka bir dosya
import fileile içe aktarır.
Dil, hangisini yazdığını beyan etmeni istemez. Herhangi bir dosya ikisini de yapıyor olabilir.
math_helpers.py adında bir dosya düşün:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
# Geliştirirken hızlı bir deneme
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Bu dosyayı doğrudan çalıştırırsan test çıktısını yazdırır — güzel. Ama başka bir dosya import math_helpers yapsa, o print deyimleri içe aktarma sırasında çalışır. Modülü kullanan herkes senin geliştirme notlarını görür. Pek hoş değil.
__name__ Nedir
Her Python modülünün __name__ adında yerleşik bir değişkeni vardır. Python bunu otomatik ayarlar:
- Dosya içe aktarıldığında,
__name__, modülün içe aktarma adına ayarlanır — yukarıdaki örnekte"math_helpers". - Dosya doğrudan çalıştırıldığında, Python
__name__'i özel"__main__"string'ine ayarlar.
Bu sana hangi modda olduğunu anlamanın bir yolunu verir. "Yalnızca script" kodunu bir kontrolle sar:
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
if __name__ == "__main__":
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Artık python3 math_helpers.py test çıktısını yazdırır. Ama başka bir dosyadan import math_helpers yapmak bloğu tamamen atlar — fonksiyonlar kullanılabilir ve istenmeyen hiçbir şey çalışmaz.
Yaygın Tamamlayıcı: main() Fonksiyonu
Çoğu gerçek script, kendine ait bir main() fonksiyonu büyütür ve koruma bloğunu minik tutar:
# process_orders.py
import sys
def load_orders(path):
with open(path) as f:
return [line.strip() for line in f if line.strip()]
def process(orders):
for order in orders:
print(f"Processing {order}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 process_orders.py <file>")
sys.exit(1)
orders = load_orders(sys.argv[1])
process(orders)
if __name__ == "__main__":
main()
Mantığı doğrudan if korumasının altına koymak yerine neden main() için uğraşasın?
- Test edilebilirlik. Modülü içe aktarıp testlerden
main()'i (veya yardımcılarından herhangi birini) çağırabilirsin. - Yerel değişkenler.
main()içinde tanımlanan her şey yerel değişkendir, modül düzeyinde bir isim değil. Bu, kazara isim çakışmalarını önler ve modülün dışa açık yüzeyini temiz tutar. - Okunabilirlik. Koruma bloğu artık iki satırdır — bir yığın mantık değil, net bir "script giriş noktası".
Hızlı Bir Gösterim
Davranışı doğrudan görebilirsin:
Yukarıdaki parçacığı Python ile çalıştırdığında __name__ is: __main__ ve "script olarak çalıştırılıyor" yazar. Başka bir dosya bunu içe aktarsaydı, aynı kontrol diğer dalı yazdırırdı.
Korumaya İhtiyacın Olmadığı Yerler
Pek çok Python dosyası hiç büyümez. Hiç kimsenin içe aktarmayacağı kısa script'ler bunsuz da gayet iyidir:
# one_off_rename.py
import os
for name in os.listdir("."):
if name.endswith(".txt"):
os.rename(name, name.lower())
Bu gayet yeterli. Bir kütüphane kurmuyorsun; kimse bunu içe aktarmayacak. Ama bir dosyada yeniden kullanılabilir mantık olduğu an — ve onun yanında yan etkili kod da tutmak istiyorsan — korumaya uzan.
Kurulu Paketler İçin Giriş Noktaları
Kodunu gerçek bir paket olarak yayınlamaya başladığında daha resmi bir mekanizma vardır: paket meta verindeki entry_points, bir komutu bir fonksiyona eşler. Paketini kuran kullanıcılar, fonksiyonu doğrudan çağıran bir shell komutu alır. Ama kendi makinendeki bir klasörden çalışan script'ler için __main__ koruması standart araçtır.
Bu Bölümü Toparlarken
Artık elinde şunlar var:
- Mantığına isim vermek için fonksiyonlar.
- Esnek çağrılar için
*args/**kwargs. - Tek kullanımlık fonksiyonlar için lambda'lar.
- Fonksiyonları sarmak ve belgelemek için decorator'lar ve tip ipuçları.
- Kodu dosyalar ve projeler arasında bölmek için modüller, pip ve sanal ortamlar.
- Script'lerin ve modüllerin bir arada yaşamasını sağlayan
__main__koruması.
Sırada: Sınıflar
Şimdiye kadar fonksiyonları çoğunlukla düz verilerle — dict'ler, list'ler, tuple'lar — eşleştirdin. Bir sonraki bölüm sınıfları tanıtıyor; Python'un veriyi ve davranışı bir araya getirme yolu ve self, __init__, kalıtım ve dataclass gibi kavramların yaşadığı yer.
Sıkça Sorulan Sorular
if __name__ == '__main__' ne yapar?
if __name__ == '__main__' ne yapar?Altındaki bloğu yalnızca dosya doğrudan çalıştırıldığında çalıştırır (dosya bir modül olarak içe aktarıldığında değil). Bu sayede hem script olarak çalıştırılabilen hem de fonksiyonları ve sınıfları için içe aktarılabilen bir .py dosyası yazabilirsin — script eylemleri içe aktarma sırasında tetiklenmeden.
Python'un main fonksiyonuna ihtiyacı var mı?
Hayır. Python dosyaları otomatik olarak yukarıdan aşağıya çalışır. Ama bir dosyanın aynı zamanda içe aktarılabilir olmasını istediğin bir mantığı olduğu anda if __name__ == '__main__' koruması önem kazanır — ve script'in üst düzey işini bir main() fonksiyonunun içine koymak yaygın bir tamamlayıcı alışkanlıktır.
__name__ ile __main__ arasındaki fark nedir?
__name__ ile __main__ arasındaki fark nedir?__name__, Python'un her modülde ayarladığı özel bir değişkendir. Dosya içe aktarıldıysa, __name__ modülün adıdır (örneğin 'util'). Dosya doğrudan çalıştırıldıysa, Python __name__'i '__main__' string'ine ayarlar. if kontrolü bu ikisini karşılaştırır.