Đối với trường hợp đặc biệt này, các cảnh báo nhập khẩu tăng gấp đôi là do dòng này trong proj/__init__.py
:
from .proj import main
gì dòng đó có nghĩa là vào thời điểm thực hiện -m
chuyển đổi kết thúc bước import proj
, proj.proj
có đã được nhập dưới dạng tác dụng phụ của việc nhập gói gốc.
Tránh cảnh báo
Để tránh các cảnh báo, bạn cần phải tìm một cách để đảm bảo rằng việc nhập gói phụ huynh không mặc nhiên nhập khẩu các gói được thực hiện với các -m
switch.
Hai tùy chọn chính cho việc giải quyết đó là:
- Thả dòng
from .proj import main
(như @ John Moutafis gợi ý), giả định rằng có thể được thực hiện mà không vi phạm đảm bảo khả năng tương thích API; hoặc
Xóa khối if __name__ == "__main__":
từ proj
submodule và thay thế bằng một file riêng biệt proj/__main__.py
rằng chỉ cần làm:
from .proj import main
main()
Nếu bạn đi với phương án 2, sau đó dòng lệnh gọi trình cũng sẽ thay đổi chỉ là python -m proj
, thay vì tham chiếu một mô-đun con.
Một biến thể tương thích ngược hơn của phương án 2 là thêm __main__.py
mà không xóa các khối CLI từ submodule hiện tại, và đó có thể là một cách tiếp cận đặc biệt tốt khi kết hợp với DeprecationWarning
:
if __name__ == "__main__":
import warnings
warnings.warn("use 'python -m proj', not 'python -m proj.proj'", DeprecationWarning)
main()
Nếu proj/__main__.py
đã được sử dụng cho một số mục đích khác, sau đó bạn cũng có thể làm những việc như thay thế python -m proj.proj
với python -m proj.proj_cli
, nơi proj/proj_cli.py
trông giống như:
if __name__ != "__main__":
raise RuntimeError("Only for use with the -m switch, not as a Python API")
from .proj import main
main()
Tại sao cảnh báo lại tồn tại?
Cảnh báo này được phát ra khi thực hiện -m
chuyển đổi là về để đi và chạy mã một module đã nhập khẩu của lại trong module __main__
, có nghĩa là bạn sẽ có hai bản sao riêng biệt của tất cả mọi thứ nó xác định - các lớp học, chức năng, vùng chứa, v.v.
Tùy thuộc vào chi tiết cụ thể của ứng dụng, điều này có thể hoạt động tốt (đó là lý do cảnh báo thay vì lỗi) hoặc có thể dẫn đến hành vi kỳ lạ như sửa đổi trạng thái cấp mô-đun không được chia sẻ như mong đợi , hoặc thậm chí các ngoại lệ không bị bắt vì trình xử lý ngoại lệ đã cố bắt loại ngoại lệ từ một cá thể của mô đun, trong khi ngoại lệ được nâng lên đã sử dụng loại từ trường hợp khác.
Do đó cảnh báo this may cause unpredictable behaviour
mơ hồ - nếu mọi thứ xảy ra sai do chạy mã cấp cao nhất của mô-đun hai lần, các triệu chứng có thể là khá nhiều.
Làm cách nào bạn có thể gỡ lỗi các trường hợp phức tạp hơn?
Trong thời gian ở ví dụ cụ thể này, việc nhập khẩu tác dụng phụ là trực tiếp trong proj/__init__.py
, có một xa tinh tế hơn và khó debug biến nơi gói cha mẹ thay vì thực hiện:
import some_other_module
và sau đó nó là some_other_module
(hoặc một module mà nó nhập khẩu) có quyền này:
import proj.proj # or "from proj import proj"
Giả sử các hành vi sai trái là tái sản xuất, con đường chính để gỡ lỗi các loại vấn đề là chạy python trong chế độ verbose và ch eck chuỗi nhập:
$ python -v -c "print('Hello')" 2>&1 | grep '^import'
import zipimport # builtin
import site # precompiled from /usr/lib64/python2.7/site.pyc
import os # precompiled from /usr/lib64/python2.7/os.pyc
import errno # builtin
import posix # builtin
import posixpath # precompiled from /usr/lib64/python2.7/posixpath.pyc
import stat # precompiled from /usr/lib64/python2.7/stat.pyc
import genericpath # precompiled from /usr/lib64/python2.7/genericpath.pyc
import warnings # precompiled from /usr/lib64/python2.7/warnings.pyc
import linecache # precompiled from /usr/lib64/python2.7/linecache.pyc
import types # precompiled from /usr/lib64/python2.7/types.pyc
import UserDict # precompiled from /usr/lib64/python2.7/UserDict.pyc
import _abcoll # precompiled from /usr/lib64/python2.7/_abcoll.pyc
import abC# precompiled from /usr/lib64/python2.7/abc.pyc
import _weakrefset # precompiled from /usr/lib64/python2.7/_weakrefset.pyc
import _weakref # builtin
import copy_reg # precompiled from /usr/lib64/python2.7/copy_reg.pyc
import traceback # precompiled from /usr/lib64/python2.7/traceback.pyc
import sysconfig # precompiled from /usr/lib64/python2.7/sysconfig.pyc
import re # precompiled from /usr/lib64/python2.7/re.pyc
import sre_compile # precompiled from /usr/lib64/python2.7/sre_compile.pyc
import _sre # builtin
import sre_parse # precompiled from /usr/lib64/python2.7/sre_parse.pyc
import sre_constants # precompiled from /usr/lib64/python2.7/sre_constants.pyc
import _locale # dynamically loaded from /usr/lib64/python2.7/lib-dynload/_localemodule.so
import _sysconfigdata # precompiled from /usr/lib64/python2.7/_sysconfigdata.pyc
import abrt_exception_handler # precompiled from /usr/lib64/python2.7/site-packages/abrt_exception_handler.pyc
import encodings # directory /usr/lib64/python2.7/encodings
import encodings # precompiled from /usr/lib64/python2.7/encodings/__init__.pyc
import codecs # precompiled from /usr/lib64/python2.7/codecs.pyc
import _codecs # builtin
import encodings.aliases # precompiled from /usr/lib64/python2.7/encodings/aliases.pyc
import encodings.utf_8 # precompiled from /usr/lib64/python2.7/encodings/utf_8.pyc
Ví dụ cụ thể này chỉ hiển thị bộ nhập cơ sở Python 2.7 trên Fedora khi khởi động. Khi gỡ lỗi nhập hai lần RuntimeWarning
giống như câu hỏi trong câu hỏi này, bạn sẽ tìm kiếm cụm từ "nhập proj" và sau đó "nhập proj.proj" vào đầu ra tiết, và sau đó xem xét kỹ nhập khẩu ngay trước " nhập khẩu proj.proj "dòng.
Cảm ơn câu trả lời của bạn. Thật không may, điều đó không giải quyết được vấn đề. Mặc dù gợi ý của bạn có ý nghĩa hoàn hảo nhưng tôi vẫn thấy thông báo chính xác sau khi xóa dòng 'sys.path.insert'. – Matthew
Tôi đã thêm một đề xuất khác vào câu trả lời, có một cái nhìn. –