Bir alt dizinden dosya içe aktarılsın mı?


456

Adlı bir tester.pydosyam var /project.

/projectadlı bir alt dizine sahiptir ve şu libdosyaya sahiptir BoxTime.py:

/project/tester.py
/project/lib/BoxTime.py

Ben almak istiyorum BoxTimeden tester. Bunu denedim:

import lib.BoxTime

Hangi sonuçlandı:

Traceback (most recent call last):
  File "./tester.py", line 3, in <module>
    import lib.BoxTime
ImportError: No module named lib.BoxTime

BoxTimeAlt dizinden nasıl içe aktarılacağına dair bir fikriniz var mı?

DÜZENLE

__init__.pySorun, ama bakın unutmayın BoxTimeolarak lib.BoxTimeveya kullanım:

import lib.BoxTime as BT
...
BT.bt_function()

Yanıtlar:


536

Paket belgelerine (Bölüm 6.4) buradan bakın: http://docs.python.org/tutorial/modules.html

Kısacası, adında boş bir dosya koymanız gerekir

__init__.py

"lib" dizininde.


59
Neden acayip hissediyor ? Python güvenli / kullanılabilir ithalat dizinlerini işaretleme yöntemidir.
IAbstract

7
Yalnızca güvenli / kullanılabilir alma dizinlerini işaretlemez, aynı zamanda bir dizin adını alırken bazı başlatma kodlarını çalıştırmanın bir yolunu sunar.
Sadjad

32
Evet, bu hileli ve hatta kirli ve bence dil, dosya sistemini dosya sistemine yükleme yolunu dayatmamalıdır. PHP'de, kullanıcı alanı kodunun bir ad alanı / sınıf eksik olduğunda çağrılan birden çok otomatik yükleme işlevini kaydetmesine izin vererek sorunu çözdük. Daha sonra topluluk PSR-4 standardını üretti ve Composer bunu uyguladı ve bugünlerde kimse bunun için endişelenmek zorunda değil. Ve aptal sabit kodlu __init__dosyalar yok (ancak isterseniz, otomatik yükleme kancası kaydedin! Bu, hacky ve hackable arasındaki farktır ).
Morgan Touverey

4
@ AurélienOomsimport sys, os; sys.path.insert(0, os.path.abspath('..')); from sibling_package.hacks import HackyHackHack
jbowman

4
python dağınık biri :)
Jimmy Pettersson

174
  • Adlı bir alt dizin oluşturun lib.
  • Adlı boş bir dosya oluşturun lib\__init__.py.
  • İçinde lib\BoxTime.py, foo()böyle bir işlev yazın :

    def foo():
        print "foo!"
  • Yukarıdaki dizindeki istemci kodunuza şunu libyazın:

    from lib import BoxTime
    BoxTime.foo()
  • İstemci kodunuzu çalıştırın. Alacaksın:

    foo!

Çok sonra - linux'da şöyle görünecektir:

% cd ~/tmp
% mkdir lib
% touch lib/__init__.py
% cat > lib/BoxTime.py << EOF
heredoc> def foo():
heredoc>     print "foo!"
heredoc> EOF
% tree lib
lib
├── BoxTime.py
└── __init__.py

0 directories, 2 files
% python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from lib import BoxTime
>>> BoxTime.foo()
foo!

2
Bunun açıklandığı Python belgelerine bir bağlantı verebilir misiniz? Teşekkürler!
Zenon

5
Bu bağlantıyı tıklanabilir yapalım: docs.python.org/3/tutorial/modules.html#packages
Gabriel Staples

Bir paketi uygulamak için iyi bir lib
MasterControlProgram

lütfen aklınızda bulundurun: alt dizinler tire veya nokta içermemelidir, ancak alt çizgiler geçerlidir. benim için diğer sembol isimleri ile aynı kısıtlamalar gibi görünüyor, ama henüz belge seviyesine kazılmış değil.
Alexander Stohr

underscores => python3 (yorumu düzenlemek için çok geç)
Alexander Stohr

68

Yerleştirmeyi deneyebilirsiniz sys.path:

sys.path.insert(0, './lib')
import BoxTime

11
Herhangi bir nedenle init .py dosyasını oluşturamazsanız veya oluşturmayacaksanız bu harikadır .
jpihl

1
Eğer "proje" dizininden python çalıştırırsanız çalışır. "." yürüttüğünüz dosyanın yaşadığı dizine göre değil, geçerli çalışma dizininize göre yorumlanır. Size Say cd /data, python ../project/tester.py. O zaman işe yaramaz.
morningstar

2
Bu benim için çalıştı. Bunu bir init .py dosyası üzerinden tercih ederim , daha temiz alma ifadeleri için yapar.
Taylor Evanson

5
Bu ÇOK daha iyi çalışır ve "doğru" çözümdür. init .py modüllü kendi alt klasörlerine sahip boto gibi paketleri dağıtır.
Dave Dopson

1
@jpihl Bu klasörden python içe aktarma modüllerine izin vermek için __init__.py adlı bir empy dosyası (en azından) oluşturmanız gerekir . Bu çözümü denedim ve mükemmel çalışıyor (v2.7.6).
m3nda

31

Bunu yazıyorum çünkü herkes bir libdizin oluşturmanız gerektiğini gösteriyor .

Alt dizininizi adlandırmanız gerekmez lib. Bunu adlandırabilirsiniz anythingbir koymak sağlanan __init__.pyiçine.

Linux kabuğuna aşağıdaki komutu girerek bunu yapabilirsiniz:

$ touch anything/__init__.py 

Şimdi bu yapıya sahipsiniz:

$ ls anything/
__init__.py
mylib.py

$ ls
main.py

Sonra alabilirsiniz mylibiçine main.pyböyle:

from anything import mylib 

mylib.myfun()

Ayrıca, aşağıdaki gibi işlevleri ve sınıfları da içe aktarabilirsiniz:

from anything.mylib import MyClass
from anything.mylib import myfun

instance = MyClass()
result = myfun()

İçine yerleştirdiğiniz herhangi bir değişken fonksiyona veya sınıfa __init__.pyda erişilebilir:

import anything

print(anything.myvar)

Veya bunun gibi:

from anything import myvar

print(myvar)

Klasör yapım utils\__init__.pyve utils\myfile.py. (Utils her iki dosyayı da içerir) İçe aktarmaya çalışıyorum from utils.myfile import myMethod. Ama anladım ModuleNotFoundError: No module named 'utils'. Ne yanlış olabilir? Not: Ben kullanıyorum Djangove içe çalışırken views.pyhangi ile aynı seviyede olduğunu utilsklasörün
Jagruti

Modülleri içe aktarırken mutlak yollar kullanmak ve programınızı aşağıdakilerle çalıştırmak mümkündürPYTHONPATH=. python path/to/program.py
nurettin

21

Lib dizininiz bir __init__.pydosya içeriyor mu?

Python, __init__.pybir dizinin modül olup olmadığını belirlemek için kullanır .


16

Deneyin import .lib.BoxTime. Daha fazla bilgi için PEP 328'deki göreceli içe aktarma hakkında bilgi edinin .


2
Daha önce sözdiziminin kullanıldığını daha önce gördüğümü sanmıyorum. Bu yöntemi kullanmak için güçlü bir neden var mı (değil)?
tgray

2
Cevap neden bu değildi. Tabii, eğer bütün paketleri yapmak istiyorsanız, bunu yapmalısınız. Ama asıl soru bu değildi.
Travis Griggs

Bu bana verir: ValueError: Pakette olmayan göreceli içe aktarma girişimi
Alex

5
Bu yalnızca içe aktardığınız dosyanın bir paketin parçası olması durumunda çalışır. Değilse, @Alex'in işaret ettiği hatayı alırsınız.
Jonathon Reinhart

8

Ben temelde tüm durumlarda kapsar ( __init__.pygöreli / yol / to / lib / klasör olduğundan emin olun ):

import sys, os
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/your/lib/folder")
import someFileNameWhichIsInTheFolder
...
somefile.foo()


Örnek:
Proje klasörünüzde var:

/root/myproject/app.py

Başka bir proje klasörünüz var:

/root/anotherproject/utils.py
/root/anotherproject/__init__.py

İçinde bulunan /root/anotherproject/utils.pyfoo işlevini kullanmak ve çağırmak istiyorsunuz .

Yani app.py ile yazıyorsunuz:

import sys, os
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../anotherproject")
import utils

utils.foo()

2
kullanıyorsanız os.pathmuhtemelen os.path.join((os.path.dirname(os.path.realpath(__file__)),'..','anotherproject')yol birleştirme işleminizde '/' kodunu yazmak yerine kullanmak istersiniz .
cowbert

Neden "../anotherproject"olmadan yapamıyorsun os.path.dirname()?
Moshe Rabaev

@MosheRabaev - os.path işlevlerini kullanmak iyi bir uygulamadır. "../Anotherproject" yazma ve kodu Windows işletim sistemine taşıma durumunda, kod kırılacaktır! os.path utils kodu üzerinde çalıştığı işletim sistemi dikkate alındığında doğru yolu nasıl döndüreceğini bilir. daha fazla bilgi için docs.python.org/2/library/os.path.html
Mercury

@MosheRabaev ve olmadan ".." kullanırsanız dirname(realpath(__file__)), komut dosyasını çalıştırdığınızda, komut dosyasının çalıştığı yere göre değil, geçerli çalışma dizininize göre yolu hesaplar.
TJ Ellis

5

Alt __init__.pydizinde / lib'de boş bir dosya oluşturun . Ve ana kodun başına ekleyin

from __future__ import absolute_import 

sonra

import lib.BoxTime as BT
...
BT.bt_function()

ya da daha iyisi

from lib.BoxTime import bt_function
...
bt_function()

0

Sadece bu cevaplara bir ektir.

Tüm alt dizinlerdeki tüm dosyaları içe aktarmak istiyorsanız , bunu dosyanızın kök dizinine ekleyebilirsiniz.

import sys, os
sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])

Ve sonra bu dosyalar geçerli dizinin içindeymiş gibi dosyaları alt dizinlerden içe aktarabilirsiniz.

Çalışma örneği

Projemde alt dizinleri olan aşağıdaki dizine sahipsem ...

.
├── a.py
├── b.py
├── c.py
├── subdirectory_a
   ├── d.py
   └── e.py
├── subdirectory_b
   └── f.py
├── subdirectory_c
   └── g.py
└── subdirectory_d
    └── h.py

Benim içinde aşağıdaki kodu koyabilirsiniz a.pydosyası

import sys, os
sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])

# And then you can import files just as if these files are inside the current directory

import b
import c
import d
import e
import f
import g
import h

Başka bir deyişle, bu kod dosyanın geldiği dizinden soyutlanır.


-1

/project/tester.py

/project/lib/BoxTime.py

dosyaya __init__.pyulaşana kadar boş dosya oluştur

/project/lib/somefolder/BoxTime.py

#lib- ihtiyaçlar iki öğe bir __init__.pyve bazı klasör adında bir dizin #somefolderiki öğe boxtime.pyve__init__.py


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.