web-gelistirme-sc.com

Modülleri ana klasörden içe aktarma

Python 2.5 kullanıyorum.

Bu benim klasör ağacım:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(Ayrıca her klasörde __init__.py var, okunabilirlik için burada belirtilmemiş)

nib modülünü life modülünün içinden nasıl içe aktarırım? Sys.path ile uğraşmadan yapmak mümkün olduğunu umuyorum.

Not: Çalışmakta olan ana modül ptdraft klasöründedir.

491
Ram Rachum

Sorunun, modülün bir üst dizinde olması ya da onun gibi bir şeyle ilgili olmadığı görülüyor.

ptdraft öğesini içeren dizini PYTHONPATH konumuna eklemeniz gerekir.

import nib 'in sizinle birlikte çalıştığını söylediniz, bu muhtemelen PYTHONPATH'e ptdraft' in kendisini (üst değil) eklediğiniz anlamına gelir.

101
hasen

Göreli ithalat kullanabilirsiniz (python> = 2.5):

from ... import nib

(Python 2.5’teki Yenilikler) PEP 328: Mutlak ve Göreli İthalat

DÜZENLE: başka bir nokta ekledi '.' iki paket yukarı gitmek

539
f3lix

Göreli ithalat (from .. import mymodule'da olduğu gibi) yalnızca bir paket içerisinde çalışır. Geçerli modülünüzün ana dizinindeki 'mymodule' dosyasını almak için:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

import mymodule

edit: __file__ niteliği her zaman verilmez. os.path.abspath(__file__) kullanmak yerine şimdi geçerli dosyanın dosya adını (ve yolunu) almak için inspect modülünü kullanmayı önerdim

229
Remi

Kardeş paketlerden yapılan ithalatla ilgili soruya da benzer bir cevap gönderdim. Bunu görebilirsiniz burada . Aşağıdakiler Python 3.6.5, (Anaconda, conda 4.5.1), Windows 10 makinesiyle test edilmiştir.

Sys.path kesmeksizin çözüm

Kurmak

Sorudakiyle aynı klasör yapısını kabul ediyorum

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

. kök klasörünü çağırıyorum ve benim durumumda C:\tmp\test_imports konumunda bulunuyor.

Adımlar

1) Kök klasöre bir setup.py ekleyin

setup.py içeriğini basit olabilir

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

Temel olarak "any" setup.py işe yarar. Bu sadece minimal bir çalışma örneğidir.

2) sanal bir ortam kullanın

Sanal ortamlara aşina iseniz, birini etkinleştirin ve bir sonraki adıma geçin. Sanal ortamların kullanımı değil kesinlikle gerekli, ancak onlar gerçekten uzun vadede size yardımcı olacaktır (1'den fazla projeniz olduğunda) devam eden ..). En temel adımlar: (root klasöründe çalıştır)

  • Sanal env oluştur
    • python -m venv venv
  • Sanal ortamı etkinleştir
    • . /venv/bin/activate (Linux) veya ./venv/Scripts/activate (Win)

Bu konuda daha fazla bilgi edinmek için, sadece "python virtual env tutorial" veya benzeri bir Google çıksın. Muhtemelen asla oluşturmak, etkinleştirmek ve devre dışı bırakmaktan başka bir komuta ihtiyacınız yoktur.

Sanal bir ortam oluşturduktan ve etkinleştirdikten sonra, konsolunuz sanal ortamın adını parantez içinde vermelidir.

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

3) pip projenizi düzenlenebilir durumda kurun

myproject kullanarak en üst seviye paket pip yükleyin. İşin püf noktası, kurulumu yaparken -e bayrağını kullanmaktır. Bu şekilde düzenlenebilir bir durumda kurulur ve .py dosyalarında yapılan tüm düzenlemeler otomatik olarak kurulu pakete dahil edilir.

Kök dizinde, çalıştır

pip install -e . (noktayı not edin, "geçerli dizin" anlamına gelir)

Ayrıca, pip freeze kullanarak da yüklendiğini görebilirsiniz.

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

4) Her içe aktarıma mainfolder ekleyerek içe aktarın

Bu örnekte, mainfolder, ptdraft olacaktır. Bu, diğer modül adlarıyla (python standart kütüphanesinden veya 3. parti modüllerden) çarpışmalarla karşılaşmamanız avantajına sahiptir.


Örnek Kullanım

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __== '__main__':
    function_from_nib()

Life.py çalışıyor

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
63
np8

Modül klasörünüzü PYTHONPATH'e eklemek işe yaramadıysa, programınızdaki Python yorumlayıcısının modülleri aradığı sys.path listesini değiştirebilirsiniz. almak için python belgeleri diyor ki:

spam adında bir modül alındığında, tercüman önce bu adı taşıyan yerleşik bir modülü arar. Bulunamadıysa, sys.path değişkeni tarafından verilen dizinler listesinde spam.py adlı bir dosyayı arar. sys.path bu konumlardan başlatıldı:

  • giriş komut dosyasını içeren dizin (veya geçerli dizini).
  • PYTHONPATH (Shell değişkeni PATH ile aynı sözdizimine sahip bir dizin adı listesi).
  • yüklemeye bağlı varsayılan.

Başlattıktan sonra Python programları sys.path öğesini değiştirebilir. Çalışmakta olan betiği içeren dizin, standart kütüphane yolunun önüne, arama yolunun başına yerleştirilir. Bu, kütüphane dizininde aynı isimde modüller yerine, o dizindeki komut dosyalarının yükleneceği anlamına gelir. Değişim amaçlanmadıkça bu bir hatadır.

Bunu bilerek, programınızda aşağıdakileri yapabilirsiniz:

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft
50
Ricardo Murillo

İşletim sistemine bağlı yolu sys.path içinde listelenen "modül arama yolu" nda kullanabilirsiniz. Böylece aşağıdaki gibi ana dizini kolayca ekleyebilirsiniz

import sys
sys.path.insert(0,'..')

Üst-üst dizin eklemek istiyorsanız,

sys.path.insert(0,'../..')
40
Shinbero

Python 2 hakkında fazla bir şey bilmiyorum.
Python 3'te, ana klasör aşağıdaki gibi eklenebilir:

import sys 
sys.path.append('..')

... ve bir tanesi bundan modülleri içe aktarabilir

34
Rob Ellenbroek

İşte basit bir cevap bu yüzden nasıl çalıştığını görebilirsiniz, küçük ve çapraz platform.
Yalnızca yerleşik modülleri kullanır (osname__, sysve inspectname__) bu nedenle çalışması gerekir
herhangi bir işletim sisteminde (OS) çünkü Python bunun için tasarlandı.

Cevap için daha kısa kod - daha az satır ve değişken

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

Bundan daha az satır için, ikinci satırı import os.path as path, sys, inspect ile değiştirin,
getsourcefile(satır 3) başlangıcına inspect. ekleyin ve ilk satırı kaldırın.
- bununla birlikte, bu modülün tamamını ithal eder, böylece daha fazla zamana, hafızaya ve kaynağa ihtiyaç duyabilir.

Cevabımın kodu ( daha uzun sürüm )

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

Bir Yığın Taşması cevabından bir örnek kullanır Akımın yolunu nasıl bulurum?
Python'da dosya çalıştırıldı mı?
çalışan kodun kaynağını (dosya adı) yerleşik bir araçla bulmak için.

from inspect import getsourcefile  
from os.path import abspath  

Daha sonra, kaynak dosyayı nerede bulmak isterseniz, sadece şunu kullanın:

abspath(getsourcefile(lambda:0))

Kodum, sys.path dosyasına bir dosya yolu ekler, python yolu listesi
çünkü bu Python'un bu klasörden modülleri içe aktarmasına izin veriyor.

Koddaki bir modülü içe aktardıktan sonra, sys.path.pop(0) dosyasını yeni bir satırda çalıştırmak iyi bir fikirdir
bu eklenen klasör, içe aktarılan başka bir modülle aynı ada sahip bir modüle sahipse
daha sonra programda. Diğer yolları değil, içe aktarmadan önce eklenen liste öğesini kaldırmanız gerekir.
Programınız diğer modülleri içe aktarmazsa, dosya yolunu silmemek güvenlidir, çünkü
bir program sona erdikten sonra (veya Python Kabuğunu yeniden başlattıktan sonra), sys.path 'da yapılan düzenlemeler kaybolur.

Bir dosya adı değişkeni hakkında notlar

Cevabım, çalışan dosya yolunu/dosya adını almak için __file__ değişkenini kullanmıyor
kodu, çünkü buradaki kullanıcılar sık ​​sık güvenilmez olarak tanımlamıştır. Kullanmamalısın
başkaları tarafından kullanılan programlarda üst klasörden modüller almak için.

Çalışmadığı bazı örnekler (alıntı b Yığın Taşması sorusu):

• o olamaz bazı platformlarda bulundu • o bazen tam dosya yolu değil

  • py2exe__file__ özelliğine sahip değildir, ancak bir geçici çözüm var
  • IDLE'den execute() ile çalıştırdığınızda, __file__ niteliği yoktur.
  • OS X 10.6 nerede NameError: global name '__file__' is not defined alırım
29
Edward

İşte sys.path içine ana dizini içeren daha genel bir çözüm (benim için çalışıyor):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
27
Mike

Benim için üst dizine erişim için en kısa ve en sevdiğim oneliner:

sys.path.append(os.path.dirname(os.getcwd()))

veya:

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd (), geçerli çalışma dizininin adını, os.path.dirname (dizin_adı) iletilen dizinin adını döndürür.

Aslında, bence Python proje mimarisi, alt dizindeki hiç kimsenin ana dizindeki herhangi bir modülü kullanmayacağı şekilde yapılmalıdır. Böyle bir şey olursa, proje ağacı hakkında yeniden düşünmeye değer.

Başka bir yol da PYTHONPATH sistem ortam değişkenine ana dizin eklemektir.

10
zviad

import sys sys.path.append('../')

7
Andong Zhan

__init__.py dosyalarının bulunduğu bir paket ortamında olmadığınızda, pathlib kütüphanesi (> = Python 3.4 dahil) ana dizinin yolunu PYTHONPATH'e eklemeyi çok özlü ve sezgisel hale getirir:

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))
6
itmatters

Yukarıda belirtilen çözümler de iyidir. Bu sorunun başka bir çözümü

Üst düzey dizinden bir şey almak istiyorsanız. Sonra,

from ...module_name import *

Ayrıca, herhangi bir modülü ana dizinden almak istiyorsanız. Sonra,

from ..module_name import *

Ayrıca, herhangi bir modülü ana dizinden almak istiyorsanız. Sonra,

from ...module_name.another_module import *

Bu şekilde, istediğiniz herhangi bir yöntemi içe aktarabilirsiniz.

6
Ravin Gupta

önceki cevapla aynı stilde - ancak daha az satırda: P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

dosya, çalıştığınız konumu döndürür

4
YFP

Bir betiği betiğin ana dizininden almak için aşağıdaki yöntemlerin işe yaradığını buldum. Örnekte, env.py içindeki işlevleri app.db paketinden içe aktarmak istiyorum.

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
2
Yu N.

Kütüphanelerle çalışın. Nib adında bir kütüphane yapın, bunu setup.py kullanarak kurun, site paketlerinde kalmasına izin verin ve sorunlarınız çözüldü. Yaptığınız her şeyi tek bir pakette yapmak zorunda değilsiniz. Parçalara ayır.

1
user3181121

Bir Linux sisteminde "life" klasöründen nib.py dosyasına yumuşak bir link oluşturabilirsiniz. Ardından, basitçe aşağıdaki gibi içe aktarabilirsiniz:

import nib
0