2012-01-28 44 views
49

Tôi có thể bị thiếu một cái gì đó rõ ràng nhưng dù sao:gói Nhập khẩu bằng Python

Khi bạn nhập một gói như os trong python, bạn có thể sử dụng bất kỳ submodules/gói con ra đặt cược. Ví dụ công trình này:

>>> import os 
>>> os.path.abspath(...) 

Tuy nhiên tôi có gói riêng tôi mà được cấu trúc như sau:

FooPackage/ 
    __init__.py 
    foo.py 

và ở đây cùng một logic không hoạt động:

>>> import FooPackage 
>>> FooPackage.foo 
AttributeError: 'module' object has no attribute 'foo' 

Tôi gì làm sai?

Trả lời

29

Bạn cần phải nhập khẩu các submodule:

import FooPackage.foo 

gì bạn đang làm là tìm kiếm foo trong FooPackage/__init__.py. Bạn có thể giải quyết nó bằng cách đặt import FooPackage.foo as foo (hoặc from . import foo) trong FooPackage/__init__.py, sau đó Python sẽ có thể tìm thấy foo ở đó. Nhưng tôi khuyên bạn nên sử dụng gợi ý đầu tiên của tôi.

+4

Như tôi đã hiểu, câu hỏi không phải là cách nhập mô-đun con - đó là lý do tại sao bạn có thể truy cập một mô-đun con của hệ điều hành mà không cần nhập mô-đun con đó và cách triển khai một cái gì đó tương tự. Chỉnh sửa: Tuy nhiên, câu trả lời của bạn sẽ làm việc – pycoder112358

55

Khi bạn nhập FooPackage, Python tìm kiếm các thư mục trên PYTHONPATH cho đến khi tìm thấy tệp có tên FooPackage.py hoặc một thư mục có tên FooPackage chứa tệp có tên __init__.py. Tuy nhiên, khi tìm thấy thư mục gói, nó không sau đó quét thư mục đó và tự động nhập tất cả các tệp .py.

Có hai lý do cho hành vi này. Đầu tiên là nhập khẩu một mô-đun thực hiện mã Python có thể mất thời gian, bộ nhớ, hoặc có tác dụng phụ. Vì vậy, bạn có thể muốn nhập a.b.c.d mà không nhất thiết phải nhập tất cả gói lớn a. Tùy thuộc vào nhà thiết kế bao bì để quyết định xem các mô-đun và gói con của họ có nhập một cách rõ ràng để chúng luôn có sẵn hay không hoặc để chương trình khách hàng có khả năng chọn và chọn những gì được tải.

Thứ hai là một chút tinh tế hơn, và cũng là một showstopper. Không có tuyên bố nhập khẩu rõ ràng (hoặc trong FooPackage/__init__.py hoặc trong chương trình khách hàng), Python không nhất thiết phải biết tên cần nhập foo.py là. Trên một trường hợp hệ thống tập tin nhạy cảm (ví dụ như sử dụng trong Windows), điều này có thể đại diện cho một mô-đun tên foo, Foo, FOO, fOo, foO, FoO, FOo, hoặc fOO. Tất cả những điều này là các mã nhận dạng Python hợp lệ, khác biệt, vì vậy Python chỉ không có đủ thông tin từ tệp một mình để biết ý của bạn là gì. Do đó, để hành xử nhất quán trên tất cả các hệ thống, nó yêu cầu một câu lệnh nhập khẩu rõ ràng ở đâu đó để làm rõ tên, ngay cả trên các hệ thống tệp nơi có sẵn thông tin đầy đủ về trường hợp.

9

Bạn cần thêm from . import foo vào tệp __init__.py trong gói của mình.

+1

(Thông tin này là trong các câu trả lời khác đã được đăng, nhưng bạn đã phải đọc qua chúng một chút. Vì vậy, tôi đã đăng nó một lần nữa như một câu trả lời đơn giản cho câu hỏi.) –

+0

Tốt hơn để sử dụng thay vào đó '__all__ = [" foo "]' –

-1

Bạn có thể nhập gói từ thư viện bằng cách sử dụng câu lệnh nhập.

cú pháp: module_name nhập khẩu

 ex: import math 

Bạn có thể nhập chỉ là một phương pháp cụ thể tạo thành một gói bằng cách sử dụng cú pháp đòn

cú pháp: từ module_name nhập khẩu function_name

 ex: from math import radians 
1

Có một số quan niệm sai lầm quan trọng cần được giải quyết, cụ thể với thuật ngữ. Đầu tiên, thông thường, khi bạn nghĩ rằng bạn đang nhập package vào trăn, những gì bạn đang thực sự nhập là module. Bạn nên sử dụng thuật ngữ package khi bạn đang suy nghĩ về cấu trúc con của hệ thống tệp giúp bạn tổ chức mã của mình. Nhưng từ góc độ mã, bất cứ khi nào bạn nhập package, Python coi nó là một mô-đun. Tất cả các gói là các mô-đun. Không phải tất cả các mô-đun đều là các gói. Một mô-đun có thuộc tính __path__ được coi là một gói.

Bạn có thể kiểm tra xem os là một mô-đun hay không. Để khẳng định điều này bạn có thể làm:

import os 
print(type(os)) # will print: <type 'module'> 

Trong ví dụ của bạn, khi bạn làm import FooPackage, FooPackage được xử lý và được coi là một mô-đun quá, và thuộc tính của nó (chức năng, các lớp học, vv) được cho là quy định tại __init__.py . Vì __init__.py của bạn trống nên không thể tìm thấy foo.

Ngoài các câu hỏi import bạn không thể sử dụng ký hiệu '.' để giải quyết các mô-đun bên trong mô-đun. Ngoại lệ duy nhất xảy ra nếu một số module được nhập vào gói __init__.py của phụ huynh dự định. Để làm cho nó rõ ràng, chúng ta hãy làm một số ví dụ ở đây:

Xem xét cấu trúc ban đầu của bạn:

FooPackage/ 
    __init__.py 
    foo.py 

Trường hợp 1: __init__.py là tệp rỗng

#FooPackage imported as a module 
import FooPackage 

#foo is not a name defined in `__init__.py`. Error 
FooPackage.foo 

#FooPackage.foo imported as a module 
import FooPackage.foo 

#Error, foo has not been imported. To be able to use foo like this, 
#you need to do: import FooPackage.foo as foo 
foo.anything 

#Not error, if anything is defined inside foo.py 
FooPackage.foo.anything 

Trường hợp 2: __init__.py có dòng import foo trong đó:

import FooPackage 

#Now this is good. `foo` is sort of considered to be an attribute of 
#FooPackage 
FooPackage.foo 

Bây giờ, giả sử rằng foo không còn là module, nhưng là function mà bạn xác định trong __init__.py. nếu bạn làm import FooPackage.foo, nó sẽ ném một lỗi nói rằng foo không phải là một mô-đun.