Geçerli olanın üzerinde bir dizinde bulunan bir dosyadaki bir sınıftan devralmak istiyorum.
Bu dosyayı göreceli olarak içe aktarmak mümkün mü?
Geçerli olanın üzerinde bir dizinde bulunan bir dosyadaki bir sınıftan devralmak istiyorum.
Bu dosyayı göreceli olarak içe aktarmak mümkün mü?
Yanıtlar:
from ..subpkg2 import mod
Python belgelerine göre: Bir paket hiyerarşisinin içindeyken, içe aktarma ifadesi belgesinin dediği gibi iki nokta kullanın :
Hangi modülün içe aktarılacağını belirtirken, modülün mutlak adını belirtmeniz gerekmez. Bir modül veya paket başka bir paket içinde yer alıyorsa, paket adını belirtmek zorunda kalmadan aynı üst paket içinde göreceli bir içe aktarma yapmak mümkündür.
from
Tam ad belirtmeden geçerli paket hiyerarşisinde ne kadar yukarı geçiş yapılacağını belirledikten sonra, belirtilen modülde veya pakette önde gelen noktaları kullanarak belirtebilirsiniz. Bir öncü nokta, içe aktarmayı yapan modülün bulunduğu geçerli paket anlamına gelir. İki nokta, bir paket seviyesi anlamına gelir . Üç nokta iki seviyeye kadar, vb. Yani pakettekifrom . import mod
bir modülden yürütürseniz ,pkg
o zaman içe aktarma ile sonuçlanacaksınızpkg.mod
. Eğerfrom ..subpkg2 import mod
içindenpkg.subpkg1
yürütürsenpkg.subpkg2.mod
. Göreli ithalat spesifikasyonu,PEP 328 .
PEP 328 , mutlak / göreli ithalat ile ilgilenir.
import sys
sys.path.append("..") # Adds higher directory to python modules path.
@ gimel cevabı doğrudur eğer sen o söz paket hiyerarşi garanti edemez. Yapamıyorsanız - gerçek ihtiyaçlarınız ifade ettiğiniz gibi ise, sadece dizinlere bağlıysa ve paketleme ile herhangi bir gerekli ilişkisi olmadan - o zaman __file__
ana dizini bulmak için çalışmanız gerekir (birkaç os.path.dirname
çağrı yapacaktır; - o dizin zaten açık değilse), sonra ( sys.path
) başa getirebilir geçici insert çok başlangıcı olarak dir söyledi sys.path
, __import__
, remove tekrar dir dedi - dağınık işi gerçekten, ama "ne zaman gerekir, yapmalısın" (ve Pyhon rekabetin bu kadar ne yapmaktan programcı durdurmak asla gerekir yapılabilir - sadece ISO C standardında gibi onun önsözünde "Ruh C" bölümünde diyor -!).
İşte sizin için işe yarayabilecek bir örnek:
import sys
import os.path
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
import module_in_parent_dir
sys.path
. pypy'deki autopath.py veya bükülmüş içindeki _preamble.py, dizinleri yukarı doğru hareket ettirirken üst düzey paketi tanımlayan bir arama kriteri kullanarak çözer.
sys.path.remove(pathYouJustAdded)
olan içe aktarmadan sonra bu yeni yolu korumak için değil gibi bir şey yapmak isteyebilirsiniz .
Modülü, geçerli dizinin tam olarak bir düzey üstünde olan bir dizinden içe aktar:
from .. import module
from .. import module
hata aldım ValueError: Öneriyi izleyerek paket dışı göreli içe aktarma girişimi
önsöz: İnsanları python'un ekosisteminde rahatlatmaya yardımcı olmak ve python'un ithalat sistemi ile herkese başarıda en iyi değişikliği vermek umuduyla önceki bir cevabı önemli ölçüde yeniden yazdım.
Bu, OP'nin sorusu için en olası durum olduğunu düşündüğüm bir paket içindeki göreli ithalatı kapsayacaktır .
Bu nedenle import foo
, kök ad alanından yazmak yerine "foo" modülünü yüklemek için yazıyoruz:
foo = dict(); # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh: # please avoid doing this
exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo) # please avoid doing this
Bu nedenle Python'u, Jython gibi sanal bir sistem sağlamadan defacto dosya sisteminin olmadığı ortama yerleştirebiliriz.
Bir dosya sisteminden ayrılmak ithalatın esnek olmasını sağlar, bu tasarım arşiv / zip dosyalarından içe aktarma, tek tonları içe aktarma, bayt kodu önbelleğe alma, cffi uzantıları, hatta uzaktan kod tanımı yüklemesi gibi şeylere izin verir.
Peki, içe aktarma bir dosya sistemine bağlı değilse "bir dizin yukarı" ne demektir? Bazı sezgisellerin dışarı almak zorunda ama içinde çalışırken biz örneğin, bunu yapabilir paketin , bazı sezgisel zaten yapar tanımlanmıştır göreli gibi ithalatı .foo
ve..foo
aynı paket içinde işi. Güzel!
Kaynak kod yükleme kalıplarınızı bir dosya sistemine içtenlikle birleştirmek istiyorsanız, bunu yapabilirsiniz. Kendi buluşsal yönteminizi seçmeniz ve bir çeşit ithalat makinesi kullanmanız gerekecek , importlib'i tavsiye ederim
Python'un importlib örneği şöyle görünür:
import importlib.util
import sys
# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'
foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)
foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton
Resmen burada mevcut harika bir örnek proje var: https://github.com/pypa/sampleproject
Python paketi, kaynak kodunuz hakkında, kaynak kodunuzu diğer bilgisayarlara nasıl kopyalayacağınızı ve kaynak kodunuzu bu sistemin yoluna nasıl entegre edeceğinizi bildiren import foo
, diğer bilgisayarlarda (yorumlayıcıdan bağımsız olarak, ana bilgisayar işletim sistemi, vb.)
foo
Bazı dizinlerde (tercihen boş bir dizin) bir paket adına sahip olalım .
some_directory/
foo.py # `if __name__ == "__main__":` lives here
Benim tercihim setup.py
kardeş olarak oluşturmaktır foo.py
, çünkü setup.py dosyasını yazmayı kolaylaştırır, ancak isterseniz setuptools'un varsayılan olarak yaptığı her şeyi değiştirmek / yönlendirmek için yapılandırma yazabilirsiniz; örneğin foo.py
bir "src /" dizini altına koymak biraz popülerdir, burada ele alınmamaktadır.
some_directory/
foo.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
py_modules=['foo'],
)
.
python3 -m pip install --editable ./ # or path/to/some_directory/
"düzenlenebilir" aka -e
, kaynak dosyaları bu dizine yüklemek için içe aktarma makinelerini yeniden yönlendirir, bunun yerine geçerli tam dosyaları yükleme ortamının kitaplığına kopyalar. Bu aynı zamanda bir geliştiricinin makinesinde davranışsal farklılıklara neden olabilir, kodunuzu test ettiğinizden emin olun! Pip dışında araçlar var, ancak pip tanıtım biri olmasını tavsiye ederim :)
Ayrıca bir modül (tek bir ".py" dosyası) yerine foo
bir "paket" (bir dizin içeren __init__.py
) yapmak istiyorum , hem "paketler" hem de "modüller" kök ad alanına yüklenebilir, modüller yuvalanmış ad alanlarına izin verir, "göreceli bir dizin yukarı" içe aktarma yapmak istiyorsak faydalıdır.
some_directory/
foo/
__init__.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
)
Ben de yapmak istiyorum foo/__main__.py
, bu python paketi bir modül olarak yürütmek için izin verir, örneğin olarak python3 -m foo
yürütmek .foo/__main__.py
__main__
some_directory/
foo/
__init__.py
__main__.py # `if __name__ == "__main__":` lives here, `def main():` too!
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
...
entry_points={
'console_scripts': [
# "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
'foo=foo.__main__:main',
]
},
)
Daha fazla modülle bunu halledelim: Temel olarak, aşağıdaki gibi bir dizin yapısına sahip olabilirsiniz:
some_directory/
bar.py # `import bar`
foo/
__init__.py # `import foo`
__main__.py
baz.py # `import foo.baz
spam/
__init__.py # `import foo.spam`
eggs.py # `import foo.spam.eggs`
setup.py
setup.py
geleneksel olarak içindeki kaynak kod hakkında meta veri bilgilerini tutar, örneğin:
foo
, ancak kısa çizgiler için alt çizgi yerine koymak popülerpython ./setup.py test
Çok geniş, bir geliştirme makinesine bir kaynak modülü takılıyorsa, c uzantılarını anında derleyebilir. Her gün bir örnek için PYPA Sample Repository's setup.py dosyasını öneriyorum
Bir yapı yapay nesnesi yayınlıyorsanız, örneğin neredeyse aynı bilgisayarları çalıştırmayı amaçlayan kodun bir kopyası varsa, needs.txt dosyası, tam bağımlılık bilgilerinin anlık görüntüsünü almanın popüler bir yoludur; burada "install_requires", minimum ve maksimum uyumlu sürümler. Ancak, hedef makinelerin neredeyse aynı olduğu göz önüne alındığında, tüm bir python önekinin bir tarball oluşturmasını şiddetle tavsiye ederim. Bu zor, buraya girmek için çok ayrıntılı olabilir. pip install
'In --target
seçeneğini kontrol edin veya olası satışlar için virtualenv aka venv.
örneğe geri dön
Foo / spam / eggs.py'den foo / baz'dan kod isteseydik, mutlak ad alanından isteyebiliriz:
import foo.baz
İleride başka bir göreceli baz
uygulama ile eggs.py'yi başka bir dizine taşıma özelliğine sahip olmak istiyorsak , aşağıdaki gibi göreli bir içe aktarma kullanabiliriz:
import ..baz
Python kodunu güvenilir bir şekilde yüklemek için, bu kodu bir modülde bulundurun ve bu modülün python kütüphanesinde kurulu olmasını sağlayın.
Kurulu modüller her zaman en üst düzey ad alanından yüklenebilir. import <name>
Resmen burada harika bir örnek proje var: https://github.com/pypa/sampleproject
Temel olarak, şöyle bir dizin yapınız olabilir:
the_foo_project/
setup.py
bar.py # `import bar`
foo/
__init__.py # `import foo`
baz.py # `import foo.baz`
faz/ # `import foo.faz`
__init__.py
daz.py # `import foo.faz.daz` ... etc.
.
Sizin beyan etmeyi unutmayın setuptools.setup()
in setup.py
,
resmi örnek: https://github.com/pypa/sampleproject/blob/master/setup.py
Bizim durumumuzda muhtemelen ihracat yapmak istiyoruz bar.py
ve foo/__init__.py
kısa örneğim:
#!/usr/bin/env python3
import setuptools
setuptools.setup(
...
py_modules=['bar'],
packages=['foo'],
...
entry_points={},
# Note, any changes to your setup.py, like adding to `packages`, or
# changing `entry_points` will require the module to be reinstalled;
# `python3 -m pip install --upgrade --editable ./the_foo_project
)
.
Şimdi modülümüzü python kütüphanesine kurabiliriz; pip ile, the_foo_project
düzenleme modunda python kitaplığınıza yükleyebilirsiniz , böylece gerçek zamanlı olarak çalışabiliriz
python3 -m pip install --editable=./the_foo_project
# if you get a permission error, you can always use
# `pip ... --user` to install in your user python library
.
Şimdi herhangi bir python bağlamından, paylaşılan py_modules ve paketlerimizi yükleyebiliriz
#!/usr/bin/env python3
import bar
import foo
print(dir(bar))
print(dir(foo))
pip install --edit foo
hemen hemen her zaman bir virtualenv içinde çalışırken modülümü her zaman kurduğumu belirtmeliyim . Neredeyse hiç takılması amaçlanmamış bir modül yazmıyorum. bir şeyi yanlış anlarsam bilmek istiyorum.
editable
yumurta bağlantıları ve kurulu python modülleri her şekilde tam olarak aynı olmadığından , toks gibi bir venv-otomatik oluşturma test paketi kullanmanın çok yararlı olduğunu da belirtmeliyim ; örneğin, düzenlenebilir bir modüle yeni bir ad alanı eklemek yol aramanızda bulunur, ancak bu setup.py dosyanızda dışa aktarılmazsa paketlenmez / kurulmaz! Kullanım durumunuzu test edin :)