代码之家  ›  专栏  ›  技术社区  ›  David

如何获取Python函数的源代码?

  •  306
  • David  · 技术社区  · 17 年前

    假设我有一个Python函数,定义如下:

    def foo(arg1,arg2):
        #do something with args
        a = arg1 + arg2
        return a
    

    我可以使用 foo.func_name . 我怎样才能以编程的方式得到它的源代码,就像我在上面输入的那样?

    11 回复  |  直到 10 年前
        1
  •  501
  •   Smart Manoj AlexP    8 年前

    如果函数来自文件系统上可用的源文件,则 inspect.getsource(foo) 可能有帮助:

    如果 foo 定义为:

    def foo(arg1,arg2):         
        #do something with args 
        a = arg1 + arg2         
        return a  
    

    然后:

    import inspect
    lines = inspect.getsource(foo)
    print(lines)
    

    返回:

    def foo(arg1,arg2):         
        #do something with args 
        a = arg1 + arg2         
        return a                
    

    但我相信,如果函数是从字符串、流或从编译文件导入编译的,则无法检索其源代码。

        2
  •  178
  •   Cœur Gustavo Armenta    9 年前

    这个 inspect module 具有从python对象检索源代码的方法。似乎只有当源位于文件中时它才起作用。如果你有这个,我想你不需要从物体上得到来源。

        3
  •  81
  •   schlamar    13 年前

    dis 如果源代码不可用,则是您的朋友:

    >>> import dis
    >>> def foo(arg1,arg2):
    ...     #do something with args
    ...     a = arg1 + arg2
    ...     return a
    ...
    >>> dis.dis(foo)
      3           0 LOAD_FAST                0 (arg1)
                  3 LOAD_FAST                1 (arg2)
                  6 BINARY_ADD
                  7 STORE_FAST               2 (a)
    
      4          10 LOAD_FAST                2 (a)
                 13 RETURN_VALUE
    
        4
  •  73
  •   prashanth    10 年前

    如果您使用的是IPython,那么您需要键入“foo??"

    In [19]: foo??
    Signature: foo(arg1, arg2)
    Source:
    def foo(arg1,arg2):
        #do something with args
        a = arg1 + arg2
        return a
    
    File:      ~/Desktop/<ipython-input-18-3174e3126506>
    Type:      function
    
        5
  •  57
  •   Mike McKerns    12 年前

    我一般都同意 inspect 是一个很好的答案,我不同意你不能得到在解释器中定义的对象的源代码。如果你使用 dill.source.getsource dill ,您可以获取函数和lambda的源,即使它们是以交互方式定义的。 它还可以从curries中定义的绑定或未绑定的类方法和函数中获取代码。。。但是,如果没有封闭对象的代码,您可能无法编译该代码。

    >>> from dill.source import getsource
    >>> 
    >>> def add(x,y):
    ...   return x+y
    ... 
    >>> squared = lambda x:x**2
    >>> 
    >>> print getsource(add)
    def add(x,y):
      return x+y
    
    >>> print getsource(squared)
    squared = lambda x:x**2
    
    >>> 
    >>> class Foo(object):
    ...   def bar(self, x):
    ...     return x*x+x
    ... 
    >>> f = Foo()
    >>> 
    >>> print getsource(f.bar)
    def bar(self, x):
        return x*x+x
    
    >>> 
    
        6
  •  21
  •   TomDotTom    11 年前

    关于鲁尼的回答:

    >>> def foo(a):
    ...    x = 2
    ...    return x + a
    
    >>> import inspect
    
    >>> inspect.getsource(foo)
    u'def foo(a):\n    x = 2\n    return x + a\n'
    
    print inspect.getsource(foo)
    def foo(a):
       x = 2
       return x + a
    

    编辑:正如@0sh指出的,这个例子使用 ipython 但并不简单 python . 但是,当从源文件导入代码时,这两种方法都可以。

        7
  •  11
  •   Szabolcs    8 年前

    你可以用 inspect 获取完整的源代码。你必须使用 getsource() 方法从 检查 模块。例如:

    import inspect
    
    def get_my_code():
        x = "abcd"
        return x
    
    print(inspect.getsource(get_my_code))
    

    你可以在下面的链接上查看更多选项。 retrieve your python code

        8
  •  6
  •   smarie    7 年前

    因为这篇文章被标记为 this other post ,我在这里回答“lambda”的情况,尽管操作不是关于lambda的。

    因此,对于没有在自己的行中定义的lambda函数: marko.ristin 的答案,您可以使用 mini-lambda 或使用 SymPy 如中所述 this answer .

    • mini-lambda 更轻,支持任何类型的操作,但仅对单个变量有效
    • SymPy 更重,但更适合数学/微积分运算。特别是它可以简化你的表达式。它还支持同一表达式中的多个变量。

    下面是你如何使用 小羊羔 :

    from mini_lambda import x, is_mini_lambda_expr
    import inspect
    
    def get_source_code_str(f):
        if is_mini_lambda_expr(f):
            return f.to_string()
        else:
            return inspect.getsource(f)
    
    # test it
    
    def foo(arg1, arg2):
        # do something with args
        a = arg1 + arg2
        return a
    
    print(get_source_code_str(foo))
    print(get_source_code_str(x ** 2))
    

    它正确地屈服

    def foo(arg1, arg2):
        # do something with args
        a = arg1 + arg2
        return a
    
    x ** 2
    

    小羊羔 documentation 详细情况。顺便说一下,我是作者;)

        9
  •  4
  •   douardo    9 年前

    总结一下:

    import inspect
    print( "".join(inspect.getsourcelines(foo)[0]))
    
        10
  •  4
  •   marko.ristin    7 年前

    请注意,只有当lambda在单独的行上给出时,接受的答案才起作用。如果将其作为参数传递给函数,并希望检索lambda作为对象的代码,则问题会变得有点棘手,因为 inspect 会给你整条线的。

    例如,考虑一个文件 test.py :

    import inspect
    
    def main():
        x, f = 3, lambda a: a + 1
        print(inspect.getsource(f))
    
    if __name__ == "__main__":
        main()
    

    执行它会给你(注意缩进!):

        x, f = 3, lambda a: a + 1
    

    要检索lambda的源代码,在我看来,最好的方法是重新解析整个源文件(使用 f.__code__.co_filename )并根据行号及其上下文匹配lambda AST节点。

    我们在按合同设计的图书馆里必须做到这一点 icontract 因为我们必须解析lambda函数,所以我们将其作为参数传递给decorators。这里的代码太多了,请看 the implementation of this function .

        11
  •  3
  •   cherplunk    14 年前

    如果您严格地自己定义函数,并且它是一个相对较短的定义,那么没有依赖关系的解决方案是在字符串中定义函数并将表达式的eval()赋给您的函数。

    例如。

    funcstring = 'lambda x: x> 5'
    func = eval(funcstring)
    

    然后可以选择将原始代码附加到函数:

    func.source = funcstring
    
        12
  •  1
  •   Aziz Alto    7 年前

    如果使用IPython,另一个选项是 ?? 在函数名之后查看其源代码。下面是一个例子:

    [nav] In [1]: def foo(arg1,arg2):
             ...:     #do something with args
             ...:     a = arg1 + arg2
             ...:     return a
    
    [nav] In [2]: foo??
    Signature: foo(arg1, arg2)
    Docstring: <no docstring>
    Source:
    def foo(arg1,arg2):
        #do something with args
        a = arg1 + arg2
        return a
    
        13
  •  0
  •   Abgan    17 年前

    相信 变量名不存储在pyc/pyd/pyo文件中,因此如果没有源文件,则无法检索确切的代码行。