Aşağıdaki gibi bir klasör yapımız var diyelim:
"""+
|__klasör_1+
| |__klasör_1_1+
| | |__test_1_1.py
| |
| |__klasör_1_2+
| | |__test_1_2.py
| |
| |__test_1.py
|
|__klasör_2+
| |__klasör_2_1+
| | |__test_2_1.py
| |
| |__klasör_2_2+
| | |__test_2_2.py
| |
| |__test_2.py
|
|__test.py"""
Örnek-1: test.py dosyasını çalıştırıyorum. test_py ile klasör_1 ve klasör_2 kardeş dosyalar oldukları için (çünkü aynı dizindeler) aşağıdaki gibi bir komut yazabiliyorum:
import klasör_1, klasör_2
Ve bu kodu çalıştırdığım zaman konsol ekranı olması gerektiği gibi ne hata veriyor ne de ekrana bir şey yazdırıyor.
Bu kez kardeş dosyaların çocuklarına yani yeğenlerine ulaşmak için aşağıdaki komutları yazıyorum:
from klasör_1 import test_1
from klasör_2 import test_2
Dosyaların içinde, kendi dosya isimlerini ekrana bastıran bir print() fonksiyonu tanımlandığı için ekrana bu modüllerin isimleri bastırılıyor. Yani yeğen modüllere de sorunsuz bir şekilde ulaşabiliyoruz.
test.py için klasör_1_1, klasör_1_2, klasör_2_1 ve klasör_2_2 klasörleri ‘‘yeğen’’ konumunda oldukları için, bu ‘‘yeğenlerden birinin çocuğuna’’ ulaşalım diyoruz ve aşağıdaki komutları yazıyoruz:
from klasör_1.klasör_1_1 import test_1_1
Yukarıda kodla yeğenin çocuğu olan test_1_1'e ulaşabiliyoruz.
Bu yapıyı bir soy ağacı gibi düşünürsek aynı yöntemle çok daha ileri gidebileceğimize dair bir sonuç çıkartıyorum. Aynı durum test_1 veya diğer test dosyaları için de geçerli. Kendileriyle kardeş olan dosyaları (yani aynı dizinde bulunan dosyaları), yeğenleri (yani bir alt klasörde bulunan dosyaları) ve kendilerinden çok daha genç nesilleri (daha da alt konumda bulunan klasörleri) import etmekte hiç bir sıkıntı yok.
Ancak benim henüz anlayamadığım bir durum var. Bunu da müsadenizle Örnek-2’de açıklamak istiyorum:
Örnek-2: Bu kez, test_1 dosyasında denemeler yapmak geliyor içimden ve kuzen dosyaya erişmeye çalışıyorum. test_1 için kuzen dosya test_2. Onu import edebilmek için aşağıdaki kodu yazıyorum:
from . import test_2
#SystemError: Parent module '' not loaded, cannot perform relative import
Bu yöntemle kuzen modüle erişemedim. Ama kardeş veya yeğen modüllere erişmekte hala bir sıkıntı yok. Şimdi benim sormak istediğim soru da tam olarak aşağıdaki durumla alakalı:
from . import modül_ismi
Nasıl bir durumda bu ‘.’ ifadesi hata vermeden başarıyla modülü import eder merak etmekteyim.
Python dökümanının şu makalesini okuyorum, diyorum ki aynen burada tarif edildiği gibi yapmaya çalış:
The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.
(Bu arada init.py'nin yazımında sağındaki ve solundaki iki tane alt çizgi görünmüyor)
Yukarıdaki Python makalesine ve birkaç kullanıcının yorumuna göre, her bir dizinin içinde init .py adlı bir dosya bulunması gerekiyormuş. Bu init dosyası en basit durumda boş da olabilir. Dökümandaki açıklamaya göre init.py dosyası Python derleyicisinin dizine bir paket olarak davranmasını sağlıyormuş.
StackOverflow adresinde konuyla ilgili bir başlık açtım. Gelen cevaplardan bir tanesi sistem yoluna (sys.path) bu modülün içinde bulunduğu dizini eklemek:
Diyelim klasör_1 içerisinde bulunan test_1.py dosyamızı çalıştırdığımızda, klasör_2’deki kuzen dosya olan test_2.py modülünü import etmek istiyoruz, bu işlemi yapabilmek için klasör_2 dizinini sistem yoluna aşağıdaki gibi eklememiz gerekiyor:
import sys
sys.path.append(“C:\\Users\\TCK\\Desktop\\örnek\\klasör_2”)
Yukarıdaki işlemden sonra test_1.py dosyamıza test_2.py dosyamızı aşağıdaki gibi import edebiliriz.
import test_2
#veya
from klasör_2_2 import test_2_2
#ancak şöyle bir kod hata verecektir.
from klasör_2 import test_2
#ImportError: No module named 'klasör_2'
#sys.path'e klasör_2'yi eklediğimiz için from klasör_2 import test_2 hata verdiren bir deyimdir.
Biz yukarıdaki kodla sistem yoluna geçici olarak bir yol atamış oluyoruz. Evet, yukarıdaki kod test_1.py dosyasına, o andaki oturum için, sistem yoluna klasör_2’yi ekleyip test_2'yi ve test_2_2'yi yukarıda yazıldıkları gibi import etme imkanı veriyor. Ancak bu ekleme kodunu silip oturumu yeniden başlattığımızda ve print(sys.path) yazdığımızda sanki az önce yapılan ekleme işlemi hiç olmamış gibi bir sonuç alıyoruz. Dolayısıyla her bir oturumda tekrar tekrar import etmek istediğimiz dizinleri yazmak zorundayız. Aynı durum test_2.py dosyası için de, diğer alt test dosyaları için de geçerli. Yani üst dizinde olan bir modüle alt dizinlerdeki modülü import etmek istediğimizde sistem yoluna ekleme yapmamız gerekmiyor. Ancak alt dizindeki bir modüle üst dizinlerdeki bir modülü eklemek istediğimizde sistem yoluna ekleme yapmamız gerekiyor.
Bu yöntem, sorunsuz bir şekilde istediğimiz modülü import etmemize yarar ancak şunu da unutmamak gerekiyor: Dosya dizinlerinde hata verdirecek bir dizin değişikliği yaparsak, hata almamak için, yaptığımız değişikliği kodlarımıza yansıtmamız gerekir.
Konuya gelen cevaplardan diğeri ise oldukça ilginç bulduğum ve henüz tam olarak nasıl yapılacağını çözemediğim bir cevap:
Mesajda bahsedilen yöntem, yazımında ‘.’ işaretini içeren import deyimiyle alakalı. Önerilen kod aşağıdaki gibi bir kod:
from …klasör_1.klasör_1_1 import test_1_1
Bu kodu çalıştırdığım zaman aşağıdaki gibi bir hata alıyorum:
SystemError: Parent module '' not loaded, cannot perform relative import
Bu mesajda daha önce de bahsettiğim hatayla aynı hata bu. Ne denediysem, bir türlü bu yöntemi kullanarak üst dizindeki bir modülü import edemedim. Belki bir yerlerde hata yapıyorumdur veya eksik bir şeyler yazıyorumdur diye düşünüyorum. Mesela bu klasör şemasının, her bir dizinine init .py adlı boş bir dosya ekledim. Yine aynı sonucu elde ettim. Bu konuyla alakalı bilgisi olan arkadaşlar varsa, yardımcı olurlarsa sevinirim. Sorunun çözümüyle alakalı bilgiler edinirsem burada paylaşırım. Son mesaj Python 3 için Türkçe Kılavuz ile pek alakalı değil gibi görünüyor, ancak diğer mesajla bağlantılı olduğunu düşünüyorum. Yine de istenirse, bu konu ayrı bir başlığa da taşınabilir. Saygılar.