Göreli ithalat in Python 3


721

Bir işlevi aynı dizindeki başka bir dosyadan almak istiyorum.

Bazen benim için işe yarıyor from .mymodule import myfunctionama bazen:

SystemError: Parent module '' not loaded, cannot perform relative import

Bazen birlikte çalışır from mymodule import myfunction, ancak bazen bir de:

SystemError: Parent module '' not loaded, cannot perform relative import

Burada mantığı anlamıyorum ve hiçbir açıklama bulamadım. Bu tamamen rastgele görünüyor.

Birisi bana tüm bunların ardındaki mantığın ne olduğunu açıklayabilir mi?


76
Bu, paketin içinde bir modülü komut dosyası olarak çalıştırdığınız anlamına gelir. Komut dosyalarını yalnızca paketin dışından çalıştırın .
Martijn Pieters

3
Muhtemelen bahsettiğiniz 'bazen' sahip olduğunuz koşulları tanımlamalısınız. Rastgele hataların olduğu anlamına gelmediğini anlıyorum.
joaquin

15
@MartijnPieters: ne yazık ki, bu modül paketin içinde olmalı ve bazen bir komut dosyası olarak da çalıştırılabilir olması gerekiyor. Bunu nasıl başarabileceğim hakkında bir fikrin var mı?
John Smith İsteğe bağlı

22
@JohnSmithOptional: Paketlerdeki komut dosyalarının karıştırılması zordur ve mümkünse kaçınılmalıdır. Paketi içe aktaran ve bunun yerine 'komut dosyası' işlevinizi çalıştıran bir sarıcı komut dosyası kullanın.
Martijn Pieters

3
Talihsiz görünüyor. Belli bir tür dosyayı ayrıştırabilen / analiz edebilen sınıflar / yöntemler içeren bir çekirdek modül yaptım ve ayrıca (esas olarak kendim için) onu alan ayrı ikincil modüller ve komut dosyalarına sahibim - bunlar bu dosyalara masaj yapabilir / dönüştürebilir. Ama aynı zamanda tek çekirdekli dosyayı (tüm karmaşık bir paketi değil) son kullanıcıya teslim edebilmeyi seviyorum, böylece kolayca dosyalarının yanına yerleştirip çalıştırabilirler. Bu "kod modunda" dosyayı ve kodlamayı ayrıştırır ve analiz eder, çeşitli alanları / değerleri / özel karakterleri toplar ve rapor verir. Ancak aslında dosyayı değiştirmez. Anti-desen?
Jon Coombs

Yanıtlar:


530

ne yazık ki, bu modülün paketin içinde olması gerekir ve bazen bir komut dosyası olarak da çalıştırılabilir olması gerekir. Bunu nasıl başarabileceğim hakkında bir fikrin var mı?

Böyle bir düzene sahip olmak oldukça yaygın ...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

... bunun mymodule.pygibi ...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

... myothermodule.pyböyle bir şey ...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

... ve bunun main.pygibi ...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

... çalıştırdığınızda iyi çalışır main.pyveya göreli içe aktarma nedeniyle mypackage/mymodule.pybaşarısız olur mypackage/myothermodule.py...

from .mymodule import as_int

Onu çalıştırman gereken yol ...

python3 -m mypackage.myothermodule

... ama biraz ayrıntılı, ve gibi bir shebang hattı ile iyi karışmaz #!/usr/bin/env python3.

Adın mymoduleküresel olarak benzersiz olduğunu varsayarak, bu durum için en basit düzeltme, göreli ithalatları kullanmaktan kaçınmak ve sadece ...

from mymodule import as_int

... benzersiz değilse veya paket yapınız daha karmaşıksa, paket dizininizi içeren dizini eklemeniz PYTHONPATHve bunu böyle yapmanız gerekir ...

from mypackage.mymodule import as_int

... ya da "kutunun dışında" çalışmasını istiyorsanız, PYTHONPATHilk önce bu kodla girebilirsiniz ...

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

Bu biraz acı verici, ama neden belirli bir Guido van Rossum tarafından yazılmış bir e-postada bir ipucu var ...

Bu konuda ve makinenin önerilen diğer twiddling'lerinde -1'im __main__ . Tek kullanımlık durum, bir modülün dizininde yaşayan ve her zaman antipattern olarak gördüğüm komut dosyaları çalıştırıyor gibi görünüyor. Fikrimi değiştirmemi sağlamak için beni bunun olmadığına ikna etmeniz gerekir.

Bir paket içindeki komut dosyalarını çalıştırmak bir antipattern olsun ya da olmasın, öznel olarak, ama kişisel olarak bazı özel wxPython widget'ları içeren bir pakette gerçekten kullanışlı buluyorum, bu yüzden wx.Framesadece bir dosya görüntülemek için kaynak dosyalardan herhangi biri için komut dosyasını çalıştırabilirim bu widget'ı test amaçlı kullanır.


7
SCRIPTDIR almak için daha iyi bir yolu verilmiştir göreli yol alma bir modülün bir açıklama olarak os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))sizin modül her zaman vardır uygun olduğunu senin emin eğer filesiz de kullanabilirsiniz os.path.realpath(os.path.dirname(__file__)).
marcz

2
Daha kısa ve okunabilir kod snippet'i uygulayarak PYTHONPATH'ınızı genişletebilirsiniz: sys.path.append( os.path.join( os.path.dirname(__file__), os.path.pardir ) )
Alex-Bogdanov

12
...which I've always seen as an antipattern.Bunun nasıl bir anti-desen olduğunu görmüyorum ... Göreceli ithalatların sezgisel bir şekilde çalışmasının çok uygun olacağı anlaşılıyor. Sadece aynı dizinde olduğunu bildiğim şeyleri içe aktarabilmek istiyorum. Akıl yürütmesinin ne olduğunu merak ediyorum
YungGun

9
Guido yine saldırıyor: Yararlı olabilecek şeyleri karıştırmak. Bu artık olmayacak.
javadba

4
Bu Python hakkında şimdiye kadar gördüğüm en üzücü şey.
AtilioA

265

açıklama

Kaynaktan PEP 328

Göreli içe aktarmalar, modülün paket hiyerarşisindeki konumunu belirlemek için bir modülün __name__ özelliğini kullanır. Modülün adı herhangi bir paket bilgisi içermiyorsa (örn. '__Main__' olarak ayarlanmışsa), göreli ithalatlar , modülün gerçekte dosya sisteminde nerede bulunduğuna bakılmaksızın modülün en üst düzey bir modülmiş gibi çözümlenir .

Bir noktada PEP 338 , PEP 328 ile çatıştı :

... göreli ithalatlar , geçerli modülün paket hiyerarşisindeki konumunu belirlemek için __name__ işlevini kullanır . Bir ana modülde __name__ değeri her zaman '__main__' olur , bu nedenle açık göreli içe aktarmalar her zaman başarısız olur (yalnızca bir paket içindeki bir modül için çalıştıklarından)

ve sorunu çözmek için PEP 366 en üst seviye değişkenini tanıttı __package__:

Yeni bir modül seviyesi özniteliği ekleyerek, bu PEP, modül -m anahtarı kullanılarak yürütülürse göreli içe aktarmaların otomatik olarak çalışmasına izin verir . Modülün kendisinde az miktarda kaynatma plakası, dosya adıyla yürütüldüğünde göreli içe aktarmaların çalışmasına izin verecektir. [...] [öznitelik] mevcut olduğunda, göreli içe aktarmalar __name__ özniteliği yerine bu özniteliğe dayalı olacaktır . [...] Ana modül dosya adıyla belirtildiğinde, __package__ özniteliği Yok olarak ayarlanır . [...] İçe aktarma sistemi __package__ set (veya None olarak ayarlanmamış) olmadan bir modülde açık bir göreceli içe aktarma ile karşılaştığında, doğru değeri hesaplar ve saklar (__name __. rpartition ('.') [0] normal modüller için ve __name__ paket başlatma modülleri için)

(benimkini vurgula)

Eğer __name__ise '__main__', __name__.rpartition('.')[0]boş dize döndürür. Hata açıklamasında boş dize hazır bilgisi olmasının nedeni budur:

SystemError: Parent module '' not loaded, cannot perform relative import

CPython PyImport_ImportModuleLevelObjectişlevinin ilgili kısmı :

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

CPython, package(paketin adı) içinde interp->modules(olarak erişilebilir ) bulamazsa bu istisnayı yükseltir sys.modules. Yana sys.modulesolan "zaten yüklenmiş olan modülleri modül isimleri eşleştiren bir sözlük" , artık o temizlemek oluyor ebeveyn modülü açıkça nispi ithalat yapmadan önce-mutlak ithal olmalıdır .

Not: Sayı 18018'deki düzeltme eki,yukarıdaki koddan önce yürütülecek başka bir ifblok ekledi:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

Eğer package(yukarıdaki ile aynı) boş bir dize, hata mesajı olacak

ImportError: attempted relative import with no known parent package

Ancak, bunu yalnızca Python 3.6 veya daha yenisinde görürsünüz.

1. Çözüm: Komut dosyanızı -m kullanarak çalıştırın

Bir dizin düşünün (Python paketi ):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

Paketteki tüm dosyalar aynı 2 kod satırıyla başlar:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

Bu iki satırı yalnızca işlemlerin sırasını açıklığa kavuşturmak için dahil ediyorum . Uygulamayı etkilemedikleri için onları tamamen görmezden gelebiliriz.

__init__.py ve module.py yalnızca bu iki satırı içerir (etkin bir şekilde boştur).

standalone.py ek olarak module.py dosyasını göreli içe aktarma yoluyla içe aktarmaya çalışır :

from . import module  # explicit relative import

/path/to/python/interpreter package/standalone.pyBaşarısız olacağının farkındayız . Ancak, biz birlikte modülü çalıştırabilirsiniz -mkomut satırı seçeneği olacaktır "arama sys.pathisimli modül için ve aynı içeriğini yürütmek __main__modülü" :

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-mtüm içe aktarma işlemlerini sizin için yapar ve otomatik olarak ayarlanır __package__, ancak bunu kendiniz de yapabilirsiniz

2. Çözüm: __package__'yi manuel olarak ayarlayın

Lütfen bunu gerçek bir çözümden ziyade bir kavram kanıtı olarak kabul edin. Gerçek dünya kodlarında kullanım için uygun değildir.

PEP 366'nın bu soruna bir çözümü vardır, ancak bu tamamlanmamıştır, çünkü __package__tek başına ayar yapmak yeterli değildir. Modül hiyerarşisinde en az N önceki paketi içe aktarmanız gerekir ; burada N , içe aktarılan modül için aranacak üst dizinlerin (komut dosyasının dizinine göre) sayısıdır.

Böylece,

  1. Geçerli modülün N'inci öncülünün üst dizininisys.path

  2. Geçerli dosyanın dizinini sys.path

  3. Geçerli modülün ana modülünü tam adını kullanarak alma

  4. 2'den__package__ tam nitelikli isme ayarlayın

  5. Göreli içe aktarmayı gerçekleştirme

1. Çözümden dosya ödünç alacağım ve daha fazla alt paket ekleyeceğim:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

Bu sefer standalone.py aşağıdaki göreli içe aktarmayı kullanarak module.py dosyasını paket paketinden içe aktarır

from ... import module  # N = 3

İşe yaraması için bu satırdan önce kazan plakası kodunu kullanmamız gerekecek.

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

Dosya adıyla standalone.py dosyasını çalıştırmamızı sağlar :

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

Bir fonksiyona sarılmış daha genel bir çözüm burada bulunabilir . Örnek kullanım:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

Çözüm # 3: Mutlak içe aktarma ve kurulum araçlarını kullanın

Adımlar -

  1. Açık göreli ithalatları, eşdeğer mutlak ithalatlarla değiştir

  2. packageİçe aktarılabilir hale getirmek için yükleyin

Örneğin, dizin yapısı aşağıdaki gibi olabilir

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

nerede setup.py olduğu

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

Geri kalan dosyalar Çözüm # 1'den ödünç alındı .

Kurulum, çalışma dizininizden bağımsız olarak paketi içe aktarmanıza izin verecektir (adlandırma sorunu olmayacağı varsayılarak).

Bu avantajı kullanmak için standalone.py dosyasını değiştirebiliriz (1. adım):

from package import module  # absolute import

Çalışma dizininizi değiştirin projectve çalıştırın /path/to/python/interpreter setup.py install --user( --userpaketi site paketleri dizininize yükler ) (2. adım):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

Artık standalone.py dosyasını komut dosyası olarak çalıştırmanın mümkün olduğunu doğrulayalım :

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

Not : Bu rotaya gitmeye karar verirseniz,paketleri tek başına yüklemekiçin sanal ortamları kullanmaktan daha iyi olur.

4.Çözüm: Mutlak ithalatlar ve bazı kaynak plakası kodları kullanın

Açıkçası, kurulum gerekli değildir - mutlak ithalatın çalışması için betiğinize bazı kaynak kodu ekleyebilirsiniz.

Çözüm # 1'den dosyalar ödünç alacağım ve standalone.py dosyasını değiştireceğim :

  1. Ana dizin ekleyin pakete kadar sys.path önce ithal şey denemeden paketin mutlak ithalatı kullanılarak:

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
  2. Göreli içe aktarmayı mutlak içe aktarma ile değiştirin:

    from package import module  # absolute import

standalone.py sorunsuz çalışır:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

Sizi uyarmam gerektiğini hissediyorum: özellikle projeniz karmaşık bir yapıya sahipse bunu yapmamaya çalışın .


Bir yan not olarak, PEP 8 mutlak ithalatın kullanılmasını tavsiye eder, ancak bazı senaryolarda açık göreli ithalatın kabul edilebilir olduğunu belirtir:

Genellikle daha okunabilir olduklarından ve daha iyi davranma eğiliminde olduklarından (veya en azından daha iyi hata mesajları verdiklerinden) mutlak ithalatlar önerilir. [...] Bununla birlikte, açık göreli ithalatlar, özellikle mutlak ithalatların gereksiz yere ayrıntılı olacağı karmaşık paket düzenleri ile uğraşırken, mutlak ithalat için kabul edilebilir bir alternatiftir.


3
Sorunu çözmek için __package__adın manuel olarak ayarlanması mümkün müdür __main__?
Paulo Scardine

Teşekkürler, güzel cevaplar! Modülü modülü kullanarak yükleyebildim impve __package__buna göre ayarladım, ancak sonuç açıkça bir anti-desen.
Paulo Scardine

Hatayı alıyorum AttributeError: 'PosixPath' object has no attribute 'path'.
kullanıcı

Hızlı cevap için teşekkürler. Nltk paketi kullanıyorum, bir hata alıyorum: nltk.decorators'den <module> dosyasında "/usr/local/lib/python3.5/dist-packages/nltk/__init__.py", satır 115 dekoratörü içe aktar, "/usr/local/lib/python3.5/dist-packages/nltk/decorators.py", 23. satırda, <module> sys.path = [sys.path içinde p için "nltk "p dosyada değil" /usr/local/lib/python3.5/dist-packages/nltk/decorators.py ", satır 23, <listcomp> sys.path = [sys.path dosyasında p için" nltk "p'de değil] TypeError: 'PosixPath' türünün argümanı yinelenemez`
kullanıcı

1
Ayrıca bir dosyayı dosya yoluna göre de aktarabilirsiniz (göreceli olarak da): docs.python.org/3/library/…
Ctrl-C

87

Bunu paketinizin __init__.py dosyasına yerleştirin :

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

Paketinizin böyle olduğunu varsayarsak:

├── project
   ├── package
      ├── __init__.py
      ├── module1.py
      └── module2.py
   └── setup.py

Şimdi paketinizde aşağıdaki gibi düzenli ithalatlar kullanın:

# in module2.py
from module1 import class1

Bu hem python 2 hem de 3'te çalışır.


1
bunu weel olarak paketlersek yapar
Alex Punnen

1
Bunun daha fazla oyu hak ettiğini düşünüyorum. Bunu her birine koymak __init__.py, temel olarak tüm göreli içe aktarma hatalarını çözecektir.
frankliuao

3
Başkaları için konuşamam, ama sys.pathdiğer kodu etkileyebileceğinden endişeliyim çünkü değiştirmek önlemek eğilimindedir . (Kısmen bunun nedeni, nasıl çalıştığının karmaşıklıklarını
bilmememdir

@pianoJames Ne demek istediğini biliyorum, bu (görünüşte, çok fazla vidalamadan sonra) sihirli düzeltme biraz fazla kolay görünüyor. Ama işe yarıyor. Bunun olumsuz yan etkileri olup olmadığını bilenlerden bilmiyorum.
Jon

Bunu şimdi kullanıyorum: ve şimdiye kadar çok iyi.
javadba

37

Bu sorunla karşılaştım. Kesmek için geçici bir çözüm aşağıdaki gibi bir if / else bloğu üzerinden içe aktarılıyor:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

29
bu çok hoş bir çözüm değil. ayrıca, çıplak except:kötü. kullanmak except ImportError:yerine!
ThiefMaster

6
Öyle SystemErrorburada. (Py 3.4)
Avi

8
Bu korkunç bir fikir değil, ancak denemek / hariç tutmak için hangi içe aktarmanın kullanılacağını tespit etmek daha iyi olurdu. Gibi bir şey if __name__ == '__main__': from mymod import as_int; else: from .mymod import as_int.
Perkins

@Perkins Pekala ... çoğu durumda olmaz . Bence göreli ithalat istisna olabilir.
wizzwizz4

8

Umarım, bu birileri için değerli olacaktır - burada yayınlanan şeylere benzer göreceli ithalatları anlamaya çalışırken yarım düzine stackoverflow yayınından geçtim. Her şeyi önerildiği gibi ayarladım ama hala vuruyordumModuleNotFoundError: No module named 'my_module_name'

Sadece yerel olarak geliştiğim ve oynadığım için bir setup.pydosya oluşturmamış / çalıştırmamıştım . Ayrıca görünüşe göre benim ayarlamamıştım PYTHONPATH.

Testler modülle aynı dizindeyken kodumu çalıştırdığımda modülümü bulamadığımı fark ettim:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

Ancak, ben açıkça şeyler yol başladığında şeyler çalışmaya başladı:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

Bu nedenle, herkesin birkaç öneri denemesi durumunda, kodunun doğru yapılandırıldığına inanıyor ve geçerli dizini PYTHONPATH'nize dışa aktarmazsanız, kendimden aşağıdakileri denemeye devam ettiğine inanıyorum:

  1. Kodunuzu çalıştırın ve yolu şu şekilde açıkça ekleyin: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. Aramadan kaçınmak için aşağıdakine benzer içerikler içeren PYTHONPATH=.bir setup.pydosya oluşturun python setup.py developmentve yola paketler eklemek için çalıştırın :
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)

6

Çalıştırmak için ana proje dizininden python3 çalıştırmak gerekiyordu.

Örneğin, proje aşağıdaki yapıya sahipse:

project_demo/
├── main.py
├── some_package/
   ├── __init__.py
   └── project_configs.py
└── test/
    └── test_project_configs.py

Çözüm

Project_demo / klasör içinde python3 çalıştırmak ve sonra bir

from some_package import project_configs

4

Bu sorunu ortadan kaldırmak için, bir süredir benim için çalışan yeniden paketleme paketi ile bir çözüm tasarladım . Üst dizini lib yoluna ekler:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

Yeniden paketleme, akıllı bir strateji (çağrı yığınını denetleme) kullanarak çok çeşitli durumlarda çalışan göreli ithalatlar yapabilir.


Şimdiye kadar en kolay çözüm! Teşekkür ederim!
CodingInCircles

1
Teşekkürler! En iyi cevabı vermeye çalışmak yerine, kullanılabilir bir cevap vermeye çalıştım :-)
fralau

3

Her iki paket de alma yolunuzda (sys.path) ve istediğiniz modül / sınıf example / example.py'de ise, göreli içe aktarma olmadan sınıfa erişmeyi deneyin:

from example.example import fkt

1

Bence en iyi çözüm modülünüz için bir paket oluşturmak: İşte nasıl yapılacağı hakkında daha fazla bilgi.

Göreli içe aktarma konusunda endişelenmenize gerek olmayan bir pakete sahip olduğunuzda, sadece mutlak ithalat yapabilirsiniz.


0

Benzer bir sorunum vardı: İşbirliği yapmak için ortak sabitleri kullanan bir Linux hizmetine ve cgi eklentisine ihtiyacım vardı. Bunu yapmanın 'doğal' yolu onları paketin init .py'sine yerleştirmektir, ancak cgi eklentisini -m parametresiyle başlatamıyorum.

Son çözümüm yukarıdaki Çözüm # 2'ye benziyordu:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

Dezavantajı, sabitleri (veya ortak işlevleri) pkg ile önek olarak eklemenizdir:

print(pkg.Glob)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.