inspect who imported me

亡梦爱人 提交于 2019-12-11 03:54:47

问题


There are two files:

# the_imported.py
import inspect
imported_by_fname = inspect.currentframe().f_back.f_code.co_filename
print('{} was imported by {}'.format(__name__, imported_by_fname))

And:

# the_importer.py
import the_imported

When executed with Python 2.7:

$ python the_importer.py 
the_imported was imported by the_importer.py

When executed with Python 3.5:

$ python3 the_importer.py 
the_imported was imported by <frozen importlib._bootstrap>

What is that weird thing <frozen importlib._bootstrap> all about? What happened with import and/or inspect that changed this behaviour? How can we get that Python 2 filename introspection working again on Python 3?


回答1:


In Python 3.1 and newer the import machinery is implemented in Python, which makes it possible to access its call stack. To illustrate this, I'll put the following code

from traceback import print_stack
print_stack()

to the_imported.py and import it.

On Python 2 that code prints

  File "the_importer.py", line 2, in <module>
    import the_imported
  File ".../the_imported.py", line 3, in <module>
    print_stack()

But on Python 3 the output is much more verbose:

  File "the_importer.py", line 2, in <module>
    import the_imported
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 677, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File ".../the_imported.py", line 2, in <module>
    print_stack()

Before Python 3.3, these lines were also included in tracebacks.

To achieve the desired result you could walk up the call stack to find the first frame, the file name of which doesn't start with <frozen importlib.

from traceback import extract_stack

for x in extract_stack():
    if not x[0].startswith('<frozen importlib'):
        print('{} was imported by {}'.format(__name__, x[0]))
        break



回答2:


There's just more on the stack in Python 3. importlib is now responsible for importing:

# the_imported.py
from inspect import getframeinfo, getouterframes, currentframe
frame = currentframe()
while frame:
    print(frame.f_code.co_filename)
    frame = frame.f_back

Output:

C:\Users\user\Desktop\the_imported.py
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
<frozen importlib._bootstrap>
C:\Users\user\Desktop\the_importer.py

You could do something like:

# the_imported.py
from inspect import getframeinfo, getouterframes, currentframe
frame = currentframe().f_back
while frame.f_code.co_filename.startswith('<frozen'):
    frame = frame.f_back
print(frame.f_code.co_filename)

Output:

C:\Users\user\Desktop\the_importer.py


来源:https://stackoverflow.com/questions/40945752/inspect-who-imported-me

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!