Python'un farklı bir klasörden içe aktarılmasını sağlayamıyorum


91

Python'un bir alt klasördeki bir modülü içe aktarmasını sağlayamıyorum. İçe aktarılan modülden sınıfın bir örneğini oluşturmaya çalıştığımda hata alıyorum, ancak içe aktarmanın kendisi başarılı oluyor. İşte benim dizin yapım:

Server
    -server.py
    -Models
        --user.py

İşte server.py'nin içeriği:

from sys import path
from os import getcwd
path.append(getcwd() + "\\models") #Yes, i'm on windows
print path
import user

u=user.User() #error on this line

Ve user.py:

class User(Entity):
    using_options(tablename='users')

    username = Field(String(15))
    password = Field(String(64))
    email    = Field(String(50))
    status   = Field(Integer)
    created  = Field(DateTime)

Hata: AttributeError: "modül" nesnesinin "Kullanıcı" özniteliği yok


1
Hata mesajını yapıştırabilir misiniz?
Harley Holcombe

User.py'den ise server.py'yi içe aktarmak istiyorum. Ben ne yaparım?
Chandra Kanth

Yanıtlar:


142

__init__.pyPython'un onu bir modül olarak ele alması için Modeller dizininde adında bir dosya oluşturmanız gerektiğine inanıyorum .

O zaman şunları yapabilirsiniz:

from Models.user import User

Kodu içine __init__.py(örneğin birkaç farklı sınıfın ihtiyaç duyduğu başlatma kodu) ekleyebilir veya boş bırakabilirsiniz. Ama orada olmalı.


2
Teşekkürler, bundan önce paketleri hiç duymamıştım.
ryeguy

1
Aslında, Python içe aktarılırken blah.py ve blah / __ init__.py tamamen aynı şekilde davranır.
pi.

2
Bu açık değildi ... Ve kendime şunu söylüyorum: RTFM FMF
Alexander.Iljushkin

1
Server.py'yi başka bir dizinden çalıştırıyorsanız bunun işe yaramayacağını unutmayın.
kchoi

1
ya server.py başka bir klasördeyse?
Mandroid

24

Sen oluşturmak zorunda __init__.pyüzerindeModels alt klasör. Dosya boş olabilir. Bir paketi tanımlar.

O zaman şunları yapabilirsiniz:

from Models.user import User

Python öğreticisindeki her şeyi burada okuyun .

Burada ayrıca python projelerinin dosya organizasyonu hakkında güzel bir makale var .


Ya dosya boş DEĞİLSE?
darkgaze

12

kullanıcıyı içe aktar

u = user.User () # bu satırdaki hata

Yukarıda belirtilen __init__ eksikliğinden dolayı, sorunu daha net hale getirecek bir ImportError olmasını beklersiniz.

Bir tane alamazsınız çünkü 'kullanıcı' aynı zamanda standart kitaplıkta mevcut bir modüldür. İçe aktarma ifadeniz bunu alır ve içindeki User sınıfını bulmaya çalışır; bu yoktur ve ancak o zaman hatayı alırsınız.

İçe aktarımınızı mutlak hale getirmek genellikle iyi bir fikirdir:

import Server.Models.user

bu tür bir belirsizlikten kaçınmak için. Nitekim Python 2.7'den 'kullanıcı içe aktar' mevcut modüle hiç göremeyecektir.

Gerçekten göreli içe aktarmalar istiyorsanız, biraz çirkin sözdizimini kullanarak bunları açıkça Python 2.5 ve üzeri sürümlerde bulundurabilirsiniz:

from .user import User

9

Standart bir paket yapınız olmadığında üst klasörde bulunan bir modülü içe aktarmanın doğru yolu şudur:

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

(son iki satırı birleştirebilirsiniz, ancak bu şekilde anlaşılması daha kolaydır).

Bu çözüm çapraz platformdur ve diğer durumlarda değişiklik gerektirmeyecek kadar geneldir.


7

__İnit__.py eksik. Python eğitiminden:

__İnit__.py dosyalarının Python'un dizinleri paketler içeriyor olarak değerlendirmesini sağlamak için gereklidir; bu, dize gibi ortak bir ada sahip dizinlerin, daha sonra modül arama yolunda ortaya çıkan geçerli modülleri istemeden gizlemesini önlemek için yapılır. En basit durumda, __init__.py yalnızca boş bir dosya olabilir, ancak paket için başlatma kodunu da çalıştırabilir veya daha sonra açıklanacak __all__ değişkenini ayarlayabilir.

Modeller dizininize __init__.py adında boş bir dosya koyun ve tümü altın olmalıdır.


1

parametreler os.path.dirname.... komutunu nasıl yazarsınız ?

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

0

Tercih ettiğim yöntem, diğer modüller tarafından kullanılan modülleri içeren her dizinde __init__.py'ye sahip olmak ve giriş noktasında sys.path'i aşağıdaki gibi geçersiz kılmaktır:

def get_path(ss):
  return os.path.join(os.path.dirname(__file__), ss)
sys.path += [
  get_path('Server'), 
  get_path('Models')
]

Bu, belirtilen dizinlerdeki dosyaların içe aktarım için görünür olmasını sağlar ve kullanıcıyı Server.py'den içe aktarabilirim.


0

Katkıda bulunanların yukarıda verdiği yanıtları inceledikten sonra - Zorglub29, Tom, Mark, Aaron McMillin, lucasamaral, JoeyZhao, Kjeld Flarup, Procyclinsur, martin.zaenker, tooty44 ve karşılaştığım sorunu hata ayıkladıktan sonra, farklı bir kullanım durumu buldum. bu sorunla karşı karşıya olduğum için. Bu nedenle herhangi birinin referansı için gözlemlerimi aşağıya ekledim.

Kodumda sınıfların döngüsel içe aktarımı vardı. Örneğin:

src
 |-- utilities.py (has Utilities class that uses Event class)  
 |-- consume_utilities.py (has Event class that uses Utilities class)
 |-- tests
      |-- test_consume_utilities.py (executes test cases that involves Event class)

Test_utilities.py'de yazılan UT'leri çalıştırmak için python -m pytest testleri / test_utilities.py çalıştırmaya çalıştığımda aşağıdaki hatayı aldım .

ImportError while importing test module '/Users/.../src/tests/test_utilities.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_utilities.py:1: in <module>
    from utilities import Utilities
...
...
E   ImportError: cannot import name 'Utilities'

Hatayı çözme şeklim, sınıfların döngüsel içe aktarımını kaldırabilmem için işlevselliği döngüsel içe aktarma sınıfında taşımak için kodumu yeniden çarpanlara ayırmaktı.

Not, __init__.py' src ' klasörümde ve ' testler ' klasörümde dosyam var ve yine de sadece kodu yeniden çarpanlara ayırarak ' ImportError'dan kurtulabildim .

Aşağıdaki stackoverflow bağlantısı, Python'daki Dairesel bağımlılık hakkında çok daha fazla ayrıntı sağlar .

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.