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.