【问题标题】:Getting the source of an object defined in a Jupyter Notebook获取 Jupyter Notebook 中定义的对象的来源
【发布时间】:2018-07-27 22:55:34
【问题描述】:

通常,如果要获取对象的来源,可以通过inspect模块获取:

import inspect
inspect.getsource(MyObject)

但是,在 Jupyter 笔记本中,这不起作用:

import inspect

class Foo:
    def __init__(self, info):
        self.info = info

a = Foo("hi")

inspect.getsource(a)

抛出错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-048b6f0c2e9b> in <module>()
      7 a = Foo("hi")
      8 
----> 9 inspect.getsource(a)

/usr/lib/python3.6/inspect.py in getsource(object)
    963     or code object.  The source code is returned as a single string.  An
    964     OSError is raised if the source code cannot be retrieved."""
--> 965     lines, lnum = getsourcelines(object)
    966     return ''.join(lines)
    967 

/usr/lib/python3.6/inspect.py in getsourcelines(object)
    950     raised if the source code cannot be retrieved."""
    951     object = unwrap(object)
--> 952     lines, lnum = findsource(object)
    953 
    954     if ismodule(object):

/usr/lib/python3.6/inspect.py in findsource(object)
    763     is raised if the source code cannot be retrieved."""
    764 
--> 765     file = getsourcefile(object)
    766     if file:
    767         # Invalidate cache if needed.

/usr/lib/python3.6/inspect.py in getsourcefile(object)
    679     Return None if no way can be identified to get the source.
    680     """
--> 681     filename = getfile(object)
    682     all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:]
    683     all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:]

/usr/lib/python3.6/inspect.py in getfile(object)
    661         return object.co_filename
    662     raise TypeError('{!r} is not a module, class, method, '
--> 663                     'function, traceback, frame, or code object'.format(object))
    664 
    665 def getmodulename(path):

TypeError: <__main__.Foo object at 0x7fb9130ee518> is not a module, class, method, function, traceback, frame, or code object

如果我尝试查找Foo 的来源(使用inspect.getsource(Foo)),我会得到:

TypeError: &lt;module '__main__'&gt; is a built-in class

如何获取 Jupyter 笔记本中定义的类的来源?

【问题讨论】:

    标签: python python-3.x jupyter-notebook inspect


    【解决方案1】:

    我发现了一种在 Jupyter Notebook 中获取类的源代码的“hacky 方式”。

    假设你有一个单元格:

    class MyClass:
        test = 2
        
        def __init__(self):
            self.L = 5
        
        def test(self, x):
            return True
        
        @classmethod
        def forward(cls, x):
            return x
    

    然后您可以使用以下方法提取代码:

    import inspect
    from IPython.core.magics.code import extract_symbols
    
    obj = MyClass
    cell_code = "".join(inspect.linecache.getlines(new_getfile(obj)))
    class_code = extract_symbols(cell_code, obj.__name__)[0][0]
    print(class_code)
    

    new_getfile 定义自 here:

    import inspect, sys
    
    def new_getfile(object, _old_getfile=inspect.getfile):
        if not inspect.isclass(object):
            return _old_getfile(object)
        
        # Lookup by parent module (as in current inspect)
        if hasattr(object, '__module__'):
            object_ = sys.modules.get(object.__module__)
            if hasattr(object_, '__file__'):
                return object_.__file__
        
        # If parent module is __main__, lookup by methods (NEW)
        for name, member in inspect.getmembers(object):
            if inspect.isfunction(member) and object.__qualname__ + '.' + member.__name__ == member.__qualname__:
                return inspect.getfile(member)
        else:
            raise TypeError('Source for {!r} not found'.format(object))
    inspect.getfile = new_getfile
    

    【讨论】:

    • 完美运行。我在开发过程中重写了一个类,而没有将第一个版本提交给 git,我很傻。然后我需要第一个版本的来源。幸运的是,我的第一个版本类仍在运行的 Jupyter 笔记本中,所以你的代码让我找回了源代码。非常感谢。
    【解决方案2】:

    使用inspect.getsource(inspect.getfile),我们可以得到一段处理这个问题的代码:

    ...
    if isclass(object):
        if hasattr(object, '__module__'):
            object = sys.modules.get(object.__module__)
            if hasattr(object, '__file__'):
                return object.__file__
        raise TypeError('{!r} is a built-in class'.format(object))
    ...
    

    似乎在 ipython 或 Jupyter 笔记本中,定义的类/函数或 __main__ 模块没有与之关联的 __file__ 属性,因此 inspect 无法检索源文件。在这种情况下,您可以在单独的 .py 文件中定义类,以便 inspect 能够检索与其关联的文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      • 2019-02-16
      • 2020-09-19
      • 1970-01-01
      • 2022-08-13
      • 2019-10-12
      • 2020-05-05
      相关资源
      最近更新 更多