Komut Dosyası ve Modül Karşılaştırması
İşte bir açıklama. Kısa sürüm, doğrudan bir Python dosyasını çalıştırmak ve bu dosyayı başka bir yerden içe aktarmak arasında büyük bir fark olmasıdır. Bir dosyanın hangi dizinde olduğunu bilmek, Python'un hangi paket içinde olduğunu düşündüğünü belirlemez. Bu, dosyayı Python'a nasıl yüklediğinize (çalıştırarak veya içe aktararak) bağlıdır.
Python dosyasını yüklemenin iki yolu vardır: en üst düzey komut dosyası olarak veya bir modül olarak. Bir dosyayı doğrudan yürütürseniz üst düzey komut dosyası olarak, örneğin python myfile.py
komut satırına yazarak yüklenir . Bunu yaparsanız python -m myfile
veya import
başka bir dosyanın içinde bir deyimle karşılaşıldığında yüklenirse modül olarak yüklenir . Bir kerede yalnızca bir üst düzey komut dosyası olabilir; üst düzey komut dosyası, işleri başlatmak için çalıştırdığınız Python dosyasıdır.
Adlandırma
Bir dosya yüklendiğinde, dosyaya bir ad verilir (bu dosya __name__
özniteliğinde saklanır ). En üst düzey komut dosyası olarak yüklendiyse adı __main__
. Bir modül olarak yüklendiyse, adı, önce parçası olan herhangi bir paket / alt paketin adlarıyla, noktalarla ayrılmış dosya adıdır.
Örneğin, örneğin:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
içe aktardıysanız moduleX
(not: içe aktarıldı , doğrudan yürütülmedi), adı olur package.subpackage1.moduleX
. İçe aktardıysanız moduleA
, adı olur package.moduleA
. Ancak, doğrudan moduleX
komut satırından çalıştırırsanız , adı bunun yerine olur __main__
ve doğrudan moduleA
komut satırından çalıştırırsanız , adı olur __main__
. Bir modül en üst düzey komut dosyası olarak çalıştırıldığında, normal adını kaybeder ve bunun yerine adı olur __main__
.
Bir modüle içerdiği paket üzerinden erişme
Ek bir kırışıklık var: modülün adı, içinde bulunduğu dizinden "doğrudan" alınıp alınmadığına veya bir paket aracılığıyla alınıp alınmadığına bağlıdır. Bu yalnızca Python'u bir dizinde çalıştırırsanız ve aynı dizinde (veya alt dizininde) bir dosyayı içe aktarmaya çalışırsanız fark yaratır. Örneğin, dizinde Python yorumlayıcısını başlatır package/subpackage1
ve sonra başlatırsanız import moduleX
adı moduleX
sadece olur moduleX
, olmaz package.subpackage1.moduleX
. Bunun nedeni, Python'un geçerli dizini başlangıçta arama yoluna eklemesidir; geçerli dizinde içe aktarılacak modülü bulursa, bu dizinin bir paketin parçası olduğunu bilmez ve paket bilgileri modül adının bir parçası olmaz.
Özel bir durum, yorumlayıcıyı etkileşimli olarak çalıştırmanızdır (örn., python
Python kodunu anında yazın ve girmeye başlayın). Bu durumda, bu etkileşimli oturumun adıdır __main__
.
Şimdi hata mesajınız için çok önemli olan şey: eğer bir modülün adında nokta yoksa bir paketin parçası sayılmaz . Dosyanın gerçekte diskte nerede olduğu önemli değil. Önemli olan tek şey adının ne olduğu ve adı nasıl yüklediğinize bağlı.
Şimdi sorunuza dahil ettiğiniz alıntıya bakın:
Göreli içe aktarmalar, modülün paket hiyerarşisindeki konumunu belirlemek için bir modülün name özniteliğini kullanır. Modülün adı herhangi bir paket bilgisi içermiyorsa (örn. 'Ana' olarak ayarlanmışsa), göreli içe aktarmalar, modülün dosya sisteminde nerede bulunduğuna bakılmaksızın modülün en üst düzey bir modülmiş gibi çözümlenir.
Göreli ithalat ...
Göreli içe aktarmalar , bir pakette nerede olduğunu belirlemek için modülün adını kullanır. Gibi göreli bir içe aktarma kullandığınızda from .. import foo
, noktalar, paket hiyerarşisinde bazı düzeylerde yükseltmeyi belirtir. Mevcut modülün adıdır Örneğin, eğer package.subpackage1.moduleX
, o zaman ..moduleA
anlamına gelecektir package.moduleA
. A'nın from .. import
çalışması için modül adının import
ifadede yer alan en az sayıda noktaya sahip olması gerekir .
... sadece bir pakette göreceli
Ancak, modülünüzün adı __main__
bir pakette olduğu kabul edilmez. Adında nokta yoktur ve bu nedenle from .. import
içinde ifadeler kullanamazsınız . Bunu yapmaya çalışırsanız, "paket dışı göreli alma" hatası alırsınız.
Komut dosyaları göreli olarak içe aktarılamaz
Muhtemelen moduleX
, komut satırından çalıştırmayı denediğiniz veya benzer bir şeydir. Bunu yaptığınızda, adı olarak ayarlandı; bu __main__
, içindeki göreli içe aktarma işleminin başarısız olacağı anlamına gelir, çünkü adı bir pakette olduğunu göstermez. Bunun, Python'u bir modülün bulunduğu dizinden çalıştırırsanız ve daha sonra bu modülü içe aktarmaya çalışırsanız da gerçekleşeceğini unutmayın, çünkü yukarıda açıklandığı gibi Python, geçerli dizinde modülü "çok erken" olduğunu fark etmeden bulacaktır. paketin bir parçası.
Ayrıca, etkileşimli yorumlayıcıyı çalıştırdığınızda, söz konusu etkileşimli oturumun "adı" nın her zaman olduğunu unutmayın __main__
. Böylece , doğrudan etkileşimli bir oturumdan göreli içe aktarma yapamazsınız . Göreli ithalat sadece modül dosyalarında kullanım içindir.
İki çözüm:
Gerçekten moduleX
doğrudan çalıştırmak istiyorsanız , ancak yine de bir paketin parçası olarak kabul edilmesini istiyorsanız, bunu yapabilirsiniz python -m package.subpackage1.moduleX
. -m
Değil üst düzey komut dosyası gibi bir modül olarak yüklemek için Python söyler.
Ya da belki de aslında istemiyorum çalıştırmak moduleX
sadece diğer bazı komut dosyasını çalıştırmak söylemek istiyorum, myfile.py
bu kullanımlar içinde işlevlerini moduleX
. Bu durumda, dizinin içine değil - myfile.py
başka bir yere koyun ve çalıştırın. Eğer içinizde gibi şeyler yaparsanız , iyi çalışır.package
myfile.py
from package.moduleA import spam
notlar
Bu çözümlerden herhangi biri için paket dizinine ( package
örneğin) Python modülü arama yolundan ( sys.path
) erişilebilir olmalıdır . Değilse, paketteki hiçbir şeyi güvenilir bir şekilde kullanamazsınız.
Python 2.6'dan bu yana, paket çözümleme amaçlı modülün "adı" yalnızca __name__
niteliklerine göre değil , özelliğine göre de belirlenir __package__
. Bu yüzden __name__
modülün "adına" atıfta bulunmak için açık sembolü kullanmaktan kaçınıyorum . Python 2.6 Bir modülün "ad" etkili bir şekilde olduğu için __package__ + '.' + __name__
, ya da sadece __name__
eğer __package__
olduğunu None
.)