Có an toàn khi bắt nhập ImportError khi cố gắng nhập các mô-đun tùy chọn không?


10

Tôi thường thấy mẫu này ít nhất một lần trong mỗi dự án Python mà tôi làm việc. Ví dụ, trong một dự án Django, điều này thường được thêm vào ở dưới cùng của tệp cài đặt cơ sở:

try:
  from .local_settings import *
except ImportError:
  pass

Cũng thế:

try:
  import simplejson as json
except ImportError:
  import json

Điều này đã luôn làm phiền tôi một chút mặc dù; Điều gì xảy ra nếu mô-đun được nhập thành công, nhưng sau đó nó tự kích hoạt ImportError? Ví dụ, trong ví dụ đầu tiên, local_settingsmô-đun tồn tại, nhưng sau đó local_settingscố gắng nhập mô-đun không tồn tại.

Đây có phải là cách an toàn nhất để nhập một mô-đun tùy chọn, có cách nào tốt hơn để đạt được chức năng này không, hay nó phụ thuộc vào ngữ cảnh / cách sử dụng (và nếu vậy, hướng dẫn để quyết định khi nào nên sử dụng phương pháp này)?

Câu trả lời:


10

Thông thường nên giả định rằng phụ thuộc tùy chọn mà bạn đang nhập có thể tự hoạt động. Có rất ít sự khác biệt giữa việc cố gắng nhập một phụ thuộc tùy chọn bị thiếu và một phụ thuộc không thể nhập được vì thiếu phụ thuộc bắc cầu bắt buộc .

Nói cách khác, tại sao chương trình của bạn cần quan tâm đến việc simplejsonkhông có sẵn vì nó không được cài đặt, hoặc vì sự phụ thuộc của simplejsonkhông được cài đặt? Dù bằng cách nào bạn cũng không thể sử dụng simplejson.

Đối với các phụ thuộc tùy chọn, tùy thuộc vào trình cài đặt gói để đảm bảo rằng phụ thuộc được cài đặt chính xác, bao gồm các phụ thuộc bắc cầu.

Đối với một cái gì đó như local_settings, thực sự có một rủi ro (nhỏ) mà một transitive ImportErrorđược che đậy. Bạn luôn có thể đăng nhập ImportErrorngoại lệ bị bắt ở cấp DEBUG hoặc tương tự để giúp dễ dàng xem lại những gì có thể đã gây ra ngoại lệ:

try:
    from .local_settings import *
except ImportError:
    log.debug('local_settings failed to import', exc_info=True)

Các logginggói sẽ bao gồm các thông tin ngoại lệ trong nhật ký để kiểm tra sau khi bạn thiết lập exc_infolà true.

Một tùy chọn khác là đưa ra cảnh báo với warningsmô-đun , thư viện chuẩn có một ImportWarninglớp cho việc này:

import warnings

try:
    from .local_settings import *
except ImportError:
    warnings.warn('local_settings failed to import', ImportWarning)

Tôi đề nghị sử dụng ImportWarning được đề cập trong các tài liệu chính thức bên cạnh hoặc thay vì đăng nhập nó.
Eray Erdin

1
@ErayErdin: điều đó phụ thuộc vào trường hợp sử dụng. Nếu mô-đun đang được nhập dưới dạng tối ưu hóa hiệu suất, bạn có thể lập luận rằng cảnh báo chỉ là tiếng ồn, đó chắc chắn không phải là một lỗi như tài liệu ImportWarninggợi ý.
Martijn Pieters

3

Điều này thường an toàn, giả sử các mô-đun của bạn không có tác dụng phụ trong thời gian nhập.

Nếu một mô-đun nhập khẩu tăng bất kỳ ngoại lệ (không chỉ ImportError) tại thời điểm nhập, nó sẽ bị xóa khỏisys.modules . Điều này có nghĩa là nếu bất kỳ mã nào khác cố gắng nhập mô-đun, nó sẽ không nhận được mô-đun khởi tạo một phần. Thay vào đó, Python sẽ cố gắng tải lại mô-đun một lần nữa và có lẽ thất bại với ImportErrortất cả các lần nữa.

Điều này có thể gây ra sự cố nếu các mô-đun của bạn có tác dụng phụ trong thời gian nhập, vì những hiệu ứng đó không được hoàn tác. Cụ thể, nếu mô-đun vi phạm nhập thành công mô-đun khác, mô-đun sau không bị xóa khỏi sys.modules. Tác dụng phụ đặc biệt này hiếm khi là một vấn đề, nhưng một số tác dụng phụ có thể gây rắc rối hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.