Şöyle anlatmaya çalışayım. Ve bu anlattıklarımı adım adım uygulayarak anlamaya çalışın.
Bir klasör oluşturacağız. Bu klasör bizim belli bir amaç için bir araya getireceğimiz python dosyalarını içerecek. Python’da aynı dizindeki python dosyaları birbirini görür. Yani a.py
ile b.py
aynı dizindeyse, a.py
dosyasını b.py
dosyasının içine aktarabilirsiniz. Bunun için bir kaç farklı içe aktarma yöntemi var. Hangisini kullanacağınız size kalmış. Bazen sadece bir modüldeki bir veya bir kaç nesneyi diğer programa aktarmak isteyebilirsiniz, bazen de modülde bulunan bütün nesneleri.
Eğer bir dizinde bir tane python dosyası, bir tane klasör varsa ve bu klasörün içinde de bir python dosyası varsa, klasörle aynı dizinde olan python dosyası, klasör içindeki python dosyasını sorunsuz bir şekilde içe aktarabilir.
Benim bir önceki mesajda bahsettiğim, birbirini görmeyen dosyalar ile alakalı. İzin verin bir örnek ile açıklamaya çalışayım.
Bu örneği Linux’e göre anlatıyorum.
İsmi ust_dizin
olan bir klasör oluşturalım. Bu ust_dizin
klasöründe dizin1
ve dizin2
isminde iki tane alt klasör olsun.
mkdir -p ust_dizin/dizin1 ust_dizin/dizin2
Bu örnekte klasör yapımız bu şekilde olursa, yapısı şuna benzeyecektir:
.
├── dizin1
└── dizin2
Buradaki .
işareti şu anda bulunduğumuz dizini temsil eder.
Bu dizin1
ve dizin2
klasörlerinin her birinde bir tane python dosyası oluşturalım.
Önce dizin1
'in içine girelim:
cd ust_dizin/dizin1
Şimdi modul1.py
isminde içinde print(f"Bu modülün adı {__file__}")
ifadesi bulunan bir Python dosyası oluşturalım.
echo "print(f'Bu modülün adı {__file__}')" > modul1.py
Şimdi de dizin1
'den dizin2
'ye geçelim ve ismi modul2.py
olan bir dosya oluşturalım. Bunun içine de modul1.py
'yi aktaralım.
Önce dizin2
'ye geçelim:
cd ../dizin2
Dosyamızı oluşturup içine modul1.py
'yi aktaralım.
echo "from ..dizin1 import modul1" > modul2.py
Şimdi tekrar ust_dizin
klasörümüze geçelim.
cd ..
Klasör yapımızın nasıl gözüktüğüne bakalım:
.
├── dizin1
│ └── modul1.py
└── dizin2
└── modul2.py
Burada dikkatinizi çekmek istediğim bir durum var. Normalde modul2.py
'yi çalıştırarak modul1.py
'yi modul2.py
'nin içine aktaramayız. Yani aktarırız ama bunun için sys.path.append
fonksiyonunu kullanarak modul1.py
'yi sys.path
listesine eklememiz gerekir. Ama biz burada bunu yapmayacağız, modul2.py
'yi ust_dizin
'de bir python dosyasının içine aktaracağız. Bu dosyanın adı __main__.py
olacak. Öncelikle __main__.py
dosyamızı oluşturalım ve modul2.py
'yi bu dosyanın içine aktarmaya çalışalım.
Burada iki satır kullanacağım için, bu sefer text dosyası oluşturmak için cat
komutunu kullanıyorum. Bunları elle de yapabilirsiniz. Ama ben burada komut satırını kullanmayı tercih edeceğim.
cat > __main__.py
Bu komutu yazdıktan sonra, bir alt satıra geçilir ve bizim dosyanın içine yazılacak metni yazmamız gerekir. Daha sonra da CTRL+D
tuşuna basarak cat
komutundan çıkarız. __main__.py
içine şunları yazacağız.
if __name__ == "__main__":
from .dizin2 import modul2
Dilerseniz klasörümüzün nasıl göründüğüne tekrar bakalım.
.
├── dizin1
│ └── modul1.py
├── dizin2
│ └── modul2.py
└── __main__.py
Buradaki if __name__ == "__main__"
ifadesi dosyamızın komut satırından çağrıldığı zamanki durumu temsil eder. Size kısaca şöyle kodla göstermeye çalışayım:
if __name__ == "__main__":
print("Dosya komut satırından çalıştırıldı.")
else:
print("Dosya bir başka dosyaya import edildi.")
İşte yukarıda da __main__.py
komut satırından çalıştırılacağı için if __name__ == "__main__":
deyimini kullandık.
Bu blokun altında dizin2
klasörünün başında bir adet .
görüyorsunuz. Bu tek nokta şuanda bulunduğumuz dizini ifade eder demiştim. __main__.py
, dizin2
ile aynı klasörde bulundukları için dizin2
'nin başına .
getiriyorum ve dizin2
'de bulunan modul2
dosyasını __main__.py
dosyasına aktarıyorum.
Son durum nedir?
modul1.py
dosyası kuzen dizindeki modul2.py
dosyasının içine from ..dizin1 import modul1
şeklinde aktarılıyor ve modul2.py
dosyası da __main__.py
dosyasının içine from .dizin2 import modul2
şeklinde aktarılıyor.
modul1
ile modul2
birbirlerini görmedikleri için iki tane nokta kullanarak bir üst dizine geçmiş oluyoruz, bu durumda from ..dizin1
ifadesi şu demek oluyor, bir üst dizindeki dizin1
klasörüne git, import modul1
ifadesi de bu dizindeki modul1
dosyasını programa aktar demek oluyor.
Bulunduğumuz dizin için tek bir nokta .
işareti kullanıyoruz, tıpkı __main__.py
dosyasına modul2
'yi aktarırken kullandığımız gibi. Bir üst dizin için iki tane nokta ..
işareti kullanıyouz, tıpkı modul2.py
dosyasına modul1.py
dosyasına aktarırken kullandığımız gibi. Şayet daha üst bir dizinden bir dosya aktarmak isteseydik bu sefer üç nokta ...
kullanacaktık. Buradaki mantık bu şekilde.
__main__.py
dosyasını doğrudan çalıştırmıyoruz. Bizim daha üst bir dizine geçip paketi çalıştırmamız lazım. Bir paketi komut satırından bir script gibi çalıştırmak için -m
parametresi kullanılır. Ve Python bu paketin __main__.py
dosyasını çalıştırır.
Dolayısıyla ust_dizin
'in yer aldığı klasöre geçmemiz gerekiyor.
cd ..
Gördüğünüz gibi komut satırında da üst dizin iki nokta ile temsil ediliyor. Ve burada komut satırını açıp şu komutu yazıyoruz:
python3 -m ust_dizin
Bu komut bizim __main__.py
dosyamızı çalıştırıyor. __main__.py
dosyası dizin2
'de yer alan modul2.py
dosyasını içe aktarıyor, modul2.py
dosyası da dizin1
'in içinde bulunan modul1.py
dosyasını içe aktarıyor. Ve sonuç olarak ekrana modul1.py
dosyasındaki print
ifadesi yazdırılıyor. O da benim bilgisayarımda şu şekilde bir çıktı verdi.
Bu modülün adı /home/tanberk/ust_dizin/dizin1/modul1.py
Bu örnekte göstermedim ama bir önceki mesajlarımda her bir dizinin içinde __init__.py
dosyalarının yer aldığını gördünüz. Aslında bu örnekte de her bir dizin için __init__.py
dosyası oluşturabilirdik, ama tıpkı yukarıdaki örneklerde olduğu gibi burada da pek bir işimize yaramayacaktı. Peki __init__.py
ne yapar, bundan size biraz bahsedeyim.
Mesela tkinter
kütüphanesini python betik dosyamızın içine aktarmak istediğimizde şunu yazıyoruz.
import tkinter
Tkinter’i programa aktardıktan sonra, içe aktardığımız dosyanın ne olduğunu öğrenmek için şöyle bir yol izleriz.
print(tkinter.__file__)
Bu yukarıdaki yöntem her modül için geçerli değil. Özellikle pyd
uzantılı python dosyaları için bu ifade olumlu sonuç vermiyor. Ama tkinter için bu söz konusu değil. Bu yukarıdaki kodun bilgisayarımdaki ekrana yazdırdığı yazı şu şekilde:
/usr/lib/python3.8/tkinter/__init__.py
Demek ki içe aktardığım dosya aslında __init__.py
dosyası. Buradaki mantık şu. Bir klasörün içinde __init__.py
oluşturursanız ve o klasörü daha üst bir dizinden python3 klasor_ismi
şeklinde çağırırsanız bu __init__.py
dosyası çalıştırılır.
Basit bir örnek yapalım:
Bir tane ismi kutuphane
olan bir dosya oluşturalım, bu klasörün içinde de __init__.py
isminde bir dosya oluşturalım. Dosyanın içine de şunları yazalım:
print(f"Bu dosyanın adı {__file__}")
Sonra kutuphane
klasörünün bulunduğu dizinde bir tane python oturumu açalım ve import kutuphane
yazalım. Programı içe aktarır aktarmaz alacağımız çıktı şuna benzer olacaktır:
Bu dosyanın adı /home/tanberk/kutuphane/__init__.py
O halde;
python3 -m klasor_ismi
, __main__.py
dosyasını çalıştırır.
Eğer bu klasor_ismi
bir python oturumunun içine import klasor_ismi
şeklinde aktarılırsa __init__.py
dosyası çalıştırılır.
Umarım anlatabilmişimdir. Burada anlattıklarımı eğer anladıysanız, yukarıdaki kodları bir daha incelemeye çalışın.