2010-08-05 29 views
39

Tôi đang cố truy cập dữ liệu của mô-đun từ bên trong __main__.py.Sử dụng các đối tượng riêng của mô-đun trong __main__.py

Cấu trúc như sau:

mymod/ 
    __init__.py 
    __main__.py 

Bây giờ, nếu tôi tiếp xúc với một biến trong __init__.py như thế này:

__all__ = ['foo'] 
foo = {'bar': 'baz'} 

Làm thế nào tôi có thể truy cập foo từ __main__.py?

+4

Lên trên! Tôi đã gặp rắc rối với điều này nhiều lần, rất đáng thất vọng khi thấy hành vi hiển nhiên như vậy không hoạt động theo cách mà người ta mong đợi. –

Trả lời

22

Bạn cần phải hoặc có các gói đã có trong sys.path, thêm thư mục chứa mymod để sys.path trong __main__.py, hoặc sử dụng các -m switch.

Để thêm mymod với các đường dẫn sẽ giống như thế này (trong __main__.py):

import sys 
import os 
path = os.path.dirname(sys.modules[__name__].__file__) 
path = os.path.join(path, '..') 
sys.path.insert(0, path) 
from myprog import function_you_referenced_from_init_file 

Sử dụng -m switch muốn:

python -m mymod 

Xem this answer để thảo luận nhiều hơn nữa.

+1

thêm 'sys.path.append (os.getcwd())' trước 'từ mymod nhập khẩu foo' hoạt động hoàn hảo, nhờ – sharvey

+0

Tôi nghĩ rằng điều này dựa vào một thực thi gói từ thư mục mẹ. Trong trường hợp này, 'python mymod'. –

+8

'sys.path.append (os.path.dirname (__ file__))' sẽ thêm thư mục của tệp đang được thực hiện vào sys.path – jdi

2

Module __init__ của a package hành vi như các thành viên của gói bản thân, do đó các đối tượng được nhập khẩu trực tiếp từ mymod:

from mymod import foo 

Hoặc

from . import foo 

nếu bạn muốn được ngắn gọn, sau đó đọc khoảng relative imports. Bạn cần phải chắc chắn rằng, như mọi khi, bạn không gọi mô-đun là mymod/__main__.py, ví dụ, như vậy sẽ ngăn chặn Python phát hiện mymod làm gói. Bạn có thể muốn xem xét distutils.

+0

Tôi muốn làm cho thư mục mô-đun thực thi được. – sharvey

+0

Vâng, tôi đã thử những gợi ý này và họ không làm việc cho tôi. –

+2

Khi tôi sử dụng 'từ. nhập khẩu foo', tôi nhận được một 'ValueError: nhập tương đối cố gắng trong non-package', và' ImportError: Không có module có tên mymod' nếu không. – sharvey

-2

Mô-đun cấu trúc thư mục như sau:

py/ 
    __init__.py 
    __main__.py 

__init__.py

#!/usr/bin/python3 
# 
# __init__.py 
# 

__all__ = ['foo'] 
foo = {'bar': 'baz'} 
info = { "package": __package__, 
     "name": __name__, 
     "locals": [x for x in locals().copy()] } 
print(info) 

__main__.py

#!/usr/bin/python3 
# 
# __main__.py 
# 

info = { "package": __package__, 
     "name": __name__, 
     "locals": [x for x in locals().copy()] } 
print(info) 
from . import info as pyinfo 
print({"pyinfo: ": pyinfo}) 

Execute module như một kịch bản bằng cách sử dụng -m cờ

$ python -m py

# the printout from the 'print(info)' command in __init__.py 
{'name': 'py', 'locals': ['__all__', '__builtins__', '__file__', '__package__', '__path__', '__name__', 'foo', '__doc__'], 'package': None} 
# the printout from the 'print(info)' command in __main__.py 
{'name': '__main__', 'locals': ['__builtins__', '__name__', '__file__', '__loader__', '__doc__', '__package__'], 'package': 'py'} 
# the printout from the 'print(pyinfo)' command in __main__.py 
{'pyinfo: ': {'name': 'py', 'locals': ['__all__', '__builtins__', '__file__', '__package__', '__path__', '__name__', 'foo', '__doc__'], 'package': None}} 
+2

Đây là câu trả lời của bạn? Làm thế nào về một chút bối cảnh hoặc mô tả để đi cùng với những gì bạn đang làm ? – jdi

+0

Đây là một hack khổng lồ và xấu xí. Sao chép các biến thông qua người dân địa phương? Hahaha xin lỗi, nhưng điều này thực sự rất buồn cười. –

1

Nếu bạn chạy các mô-đun với python -m mymod sau đó mã trong __main__.py sẽ có thể nhập khẩu từ phần còn lại của các mô-đun mà không cần phải thêm các module để sys.path.

4

Vấn đề tôi gặp nhiều nhất với loại điều này là tôi thường muốn chạy tệp __init__.py làm tập lệnh để kiểm tra các tính năng, nhưng không nên chạy các tệp này khi tải gói.Có một giải pháp hữu ích cho các đường dẫn thực hiện khác nhau giữa python <package>/__init__.pypython -m <package>.

  • $ python -m <module> thực hiện <package>/__main__.py. __init__.py không được tải.
  • $ python <package>/__init__.py chỉ cần thực thi tập lệnh __init__.py như tập lệnh thông thường.


Vấn đề

Khi chúng ta muốn __init__.py để có một khoản if __name__ == '__main__': ... rằng sử dụng cụ từ __main__.py. Chúng tôi không thể nhập __main__.py vì nó sẽ luôn nhập __main__.pyc từ đường dẫn của thông dịch viên. (Trừ khi… chúng tôi nghỉ dưỡng để nhập đường dẫn tuyệt đối, có thể gây ra nhiều mớ hỗn độn khác).


Giải pháp Một giải pháp :)

Sử dụng hai tập tin kịch bản cho các mô-đun của __main__:

<package>/ 
     __init__.py 
     __main__.py 
     main.py 

# __init__.py 

# ... 
# some code, including module methods and __all__ definitions 

__all__ = ['foo', 'bar'] 
bar = {'key': 'value'} 
def foo(): 
    return bar 
# ... 
if __name__ == '__main__': 
    from main import main 
    main.main() 

# __main__.py 

# some code...such as: 
import sys 
if (len(sys.argv) > 1 and sys.argv[1].lower() == 'option1'): 
    from main import main() 
    main('option1') 
elif (len(sys.argv) > 1 and sys.argv[1].lower() == 'option2'): 
    from main import main() 
    main('option2') 
else: 
    # do something else? 
    print 'invalid option. please use "python -m <package> option1|option2"' 

# main.py 

def main(opt = None): 
    if opt == 'option1': 
     from __init__ import foo 
     print foo() 
    elif opt == 'option2': 
     from __init__ import bar 
     print bar.keys() 
    elif opt is None: 
     print 'called from __init__' 

Hàng hóa nhập khẩu trong main.py có lẽ không lý tưởng trong trường hợp chúng tôi đang chạy từ __init__.py, như chúng ta đang nạp chúng vào phạm vi địa phương của mô-đun khác, mặc dù có tải chúng trong __init__.py đã, nhưng tải rõ ràng nên tránh tải tròn. Nếu bạn tải lại toàn bộ mô-đun __init__ trong main.py của mình, mô-đun sẽ không được tải là __main__, vì vậy phải an toàn khi tải liên tục.

Các vấn đề liên quan