Cách lấy tham chiếu đến các thuộc tính của mô-đun hiện tại bằng Python


119

Những gì tôi đang cố gắng làm sẽ giống như thế này trong dòng lệnh:

>>> import mymodule
>>> names = dir(mymodule)

Làm cách nào tôi có thể tham chiếu đến tất cả các tên được xác định mymoduletừ bên trongmymodule chính nó?

Một cái gì đó như thế này:

# mymodule.py
names = dir(__thismodule__)

Câu trả lời:


135

Chỉ cần sử dụng hình cầu ()

Gloals () - Trả về một từ điển đại diện cho bảng ký hiệu toàn cục hiện tại. Đây luôn là từ điển của mô-đun hiện tại (bên trong một hàm hoặc phương thức, đây là mô-đun nơi nó được định nghĩa, không phải là mô-đun mà từ đó nó được gọi).

http://docs.python.org/library/functions.html#globals


4
Có cách nào để truy cập vào gloabals () của mô-đun gọi, thay vì mô-đun xác định không?
dimo414

9
Bạn có thể thử lấy hình cầu của người gọi từ mô-đun theo dõi ( docs.python.org/library/traceback.html ), nhưng điều này đang đi vào lãnh thổ ma thuật đen tối. Tôi không biết bạn đang cố gắng làm gì, nhưng bạn có thể muốn suy nghĩ lại về thiết kế của mình nếu bạn cần.
Maciej Pasternacki

Một trường hợp cổ điển là "Tôi cần X (để hoàn thành Y) -> Bạn không cần X, bạn cần Z". Tôi cần X! Không có vi phạm, tôi chỉ tìm thấy điều này gây cười, và hầu hết các bình chọn câu trả lời cho tôi câu trả lời tôi cần :)
pawamoy

Điều quan trọng cần lưu ý là khối cầu () có thể trả về kết quả sai vì nó phụ thuộc vào ngữ cảnh nơi được gọi. Ví dụ: nếu thực hiện một cuộc gọi từ một hàm lớp, thì nó sẽ trả về ngữ cảnh toàn cục được liên kết với lớp, không phải bối cảnh mô-đun hiện tại, điều này có ý nghĩa khác biệt. Ngay cả khi thực hiện một cuộc gọi từ một hàm miễn phí, nó có thể trả về một bối cảnh chung của mô-đun khác, phụ thuộc vào cách hàm đã được nhập.
Andry

163

Như đã đề cập trước đây, global cung cấp cho bạn một từ điển trái ngược với dir (), cung cấp cho bạn danh sách các tên được xác định trong mô-đun. Cách tôi thường thấy việc này được thực hiện là như thế này:

import sys
dir(sys.modules[__name__])

2
Tôi sẽ thêm một nhận xét rằng điều này sẽ không hoạt động đối với mô-đun ' chính ' (là mô-đun chạy ở thiết bị đầu cuối được gọi là) bởi vì điều đó dường như không được liệt kê trong sys.modules - nhưng nó thực sự hoạt động :)
markm

Tuy nhiên, nó dường như không hoạt động từ ipdb (chèn "import ipdb; ipdb.set_trace ()" vào tệp của bạn).
gatoatigrado

9
Thông minh! Điều này chỉ cho phép tôi sử dụng docstring của mô-đun hiện tại làm thông báo sử dụng - sys.modules[__name__].__doc__.
george

Và để có được siêu hacky. operators.attrgetter('module.attribute')(sys.modules[__name__])- bạn biết đấy, nếu bạn làm những điều điên rồ mà mọi người bảo bạn không nên làm như tự động nhập các gói từ chuỗi và sau đó khỉ vá những gói đó trong khi không ở trong một lớp hoặc bất cứ điều gì ...
casey

2
Đối với bất kỳ ai đọc nhận xét của george: sys.modules[__name__].__doc__== __doc__vì điều này được xác định trong không gian tên hiện tại. Do đó, việc tìm nạp đối tượng mô-đun để truy cập các thuộc tính của chính nó là không cần thiết.
Oliver Bestwalter

1

Có thể là muộn để trả lời, nhưng tôi đã không tìm ra câu trả lời chính xác cho mình. Giải pháp gần nhất và chính xác nhất (nhanh hơn inspect.stack()) trong python 3.7.x:

  # search for first module in the stack
  stack_frame = inspect.currentframe()
  while stack_frame:
    print('***', stack_frame.f_code.co_name, stack_frame.f_code.co_filename, stack_frame.f_lineno)
    if stack_frame.f_code.co_name == '<module>':
      if stack_frame.f_code.co_filename != '<stdin>':
        caller_module = inspect.getmodule(stack_frame)
      else:
        # piped or interactive import
        caller_module = sys.modules['__main__']
      if not caller_module is None:
        #... do something here ...
      break
    stack_frame = stack_frame.f_back

Ưu điểm :

  • Preciser hơn globals()phương pháp.
  • Không phụ thuộc vào các khung trung gian ngăn xếp, có thể được thêm vào ví dụ: thông qua nối hoặc bằng các công cụ 3dparty như pytest:
*** foo ... ..
*** boo ... ..
*** runtest c:\python\x86\37\lib\site-packages\xonsh\pytest_plugin.py 58
*** pytest_runtest_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 125
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** <lambda> c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** from_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 229
*** call_runtest_hook c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** call_and_report c:\python\x86\37\lib\site-packages\_pytest\runner.py 176
*** runtestprotocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 95
*** pytest_runtest_protocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 80
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** pytest_runtestloop c:\python\x86\37\lib\site-packages\_pytest\main.py 258
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** _main c:\python\x86\37\lib\site-packages\_pytest\main.py 237
*** wrap_session c:\python\x86\37\lib\site-packages\_pytest\main.py 193
*** pytest_cmdline_main c:\python\x86\37\lib\site-packages\_pytest\main.py 230
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** main c:\python\x86\37\lib\site-packages\_pytest\config\__init__.py 90
*** <module> c:\Python\x86\37\Scripts\pytest.exe\__main__.py 7
  • Có thể xử lý phiên tương tác hoặc đường ống python.

Nhược điểm:

  • Một loại chính xác và có thể trả về các mô-đun đã đăng ký trong một tệp thực thi như cho pytest.exe có thể không phải những gì bạn muốn.
  • inspect.getmodule vẫn có thể trả về Không có trên các mô-đun hợp lệ tùy thuộc vào việc nối

Tôi có một phần mở rộng cho python: Làm cách nào để nhập một mô-đun được cung cấp đường dẫn đầy đủ?

Tiện ích mở rộng có các chức năng trình bao bọc cho trường hợp đó:

def tkl_get_stack_frame_module_by_offset(skip_stack_frames = 0, use_last_frame_on_out_of_stack = False):
  ...

def tkl_get_stack_frame_module_by_name(name = '<module>'):
  ...

Bạn chỉ cần khởi tạo tiện ích mở rộng đúng cách:

# portable import to the global space
sys.path.append(<path-to-tacklelib-module-directory>)
import tacklelib as tkl

tkl.tkl_init(tkl, global_config = {'log_import_module':os.environ.get('TACKLELIB_LOG_IMPORT_MODULE')})

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

# use `tkl_*` functions directly from here ...
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.