Python 如何确定函数是由'lambda'还是'def'声明的?

Python 如何确定函数是由'lambda'还是'def'声明的?,python,function,lambda,types,function-declaration,Python,Function,Lambda,Types,Function Declaration,如果我声明两个函数a和b: def a(x): return x**2 b = lambda x: x**2 我不能用type来区分它们,因为它们都是同一类型的 assert type(a) == type(b) 另外,types.LambdaType也没有帮助: >>> import types >>> isinstance(a, types.LambdaType) True >>> isinstance(b, types.L

如果我声明两个函数
a
b

def a(x):
    return x**2

b = lambda x: x**2
我不能用
type
来区分它们,因为它们都是同一类型的

assert type(a) == type(b)
另外,
types.LambdaType
也没有帮助:

>>> import types
>>> isinstance(a, types.LambdaType)
True
>>> isinstance(b, types.LambdaType)
True
可以使用
\uuuu name\uuuuu
如下:

def is_lambda_function(function):
    return function.__name__ == "<lambda>"

>>> is_lambda_function(a)
False
>>> is_lambda_function(b)
True

有没有一种方法可以产生比
\uu name\uuu
属性更可靠的结果?

好吧,在Python3中无法可靠地生成结果

Python2用于定义一系列函数类型。因此,方法、lambda和普通函数都有各自的类型

Python3只有一种类型,即
function
。使用
def
lambda
声明一个常规函数确实有不同的副作用:
def
将函数名(和限定名)设置为函数名,并可以设置docstring,而
lambda
将名称(和限定名)设置为
,并将docstring设置为无。但这是可以改变的

如果函数是从常规Python源代码加载的(并且不是在交互环境中键入的),则
inspect
模块允许访问原始Python代码:

import inspect

def f(x):
    return x**2

g = lambda x: x**2

def is_lambda_func(f):
    """Tests whether f was declared as a lambda.

Returns: True for a lambda, False for a function or method declared with def
Raises:
    TypeError if f in not a function
    OSError('could not get source code') if f was not declared in a Python module
                                         but (for example) in an interactive session
"""
    if not inspect.isfunction(f):
        raise TypeError('not a function')
    src = inspect.getsource(f)
    return not src.startswith('def') and not src.startswith('@') # provision for decorated funcs

g.__name__ = 'g'
g.__qualname__ = 'g'

print(f, is_lambda_func(f))
print(g, is_lambda_func(g))
这将打印:

<function f at 0x00000253957B7840> False
<function g at 0x00000253957B78C8> True

我借此机会潜入水中,看看是否能找到什么,恐怕我不得不说:你不能

简单地说,这是一个lambda在解释器中的旅程:

  • 在解析过程中,lambdas与其他所有表达式一样,是一个包含每个表达式的数据的巨大联合体
  • 然后将该
    expr\u ty
    转换为适当的类型(,在我们的例子中)
  • 过了一段时间,我们降落到了
  • 这个函数调用,它调用,它初始化(函数、方法以及lambda,都在这里结束)

  • 从这里,我看不到任何特定于lambdas的东西。这一点,再加上Python允许您修改几乎所有对象属性的事实,使我/我们相信您想要做的事情是不可能的。

    您可以检查
    \uuuuuuuuuuuuuuuuu.co\u name
    。它包含编译函数/lambda时的名称:

    defa(x):
    返回x**2
    b=λx:x**2
    def是λ函数(f):
    返回f.。\u代码\u.co\u名称=“”
    >>>is_lambda_函数(a)
    假的
    >>>is_lambda_函数(b)
    真的
    
    而且,与
    \uuuuu name\uuuuuu
    相反,
    \uuuu code\uuuu.co\u name

    >>a.。\uuuuu name=“”
    >>>b.uuu name_uuu=“b”
    >>>a.。_uu代码_uu.co_u名称=“”
    回溯(最近一次呼叫最后一次):
    文件“”,第1行,在
    AttributeError:只读属性
    >>>b._code_u.co_name=“b”
    回溯(最近一次呼叫最后一次):
    文件“”,第1行,在
    AttributeError:只读属性
    
    。。。因此,结果将保持不变:

    >>是lambda函数(a)
    假的
    >>>is_lambda_函数(b)
    真的
    
    是否有任何实际使用案例需要此功能?连同上面的其他注释,它是def还是lambda有什么区别?@JaredSmith,例如,Django无法序列化lambda。@jpp:IMHO它不是重复的!另一个问题的公认答案显然是指Python2,而Python3现在更常用。而且它不能应用在Python3中……您的用例是什么?为了进一步说明您的答案:由于
    def
    lambda
    产生无法区分的对象(特别是因为您可以自由编辑
    \uu name\uuuuuuuu
    \uuuuuu qualname\uuuuu
    ),那么不仅“不可能”执行OP要求的操作,而且没有意义。如何区分由列表理解生成的列表与由
    list
    函数创建并由
    for
    循环填充的列表之间的区别?如何区分单引号生成的字符串与双引号生成的字符串之间的区别?不能这样做,因为除了源代码级别之外,没有区别。
    <function f at 0x00000253957B7840> False
    <function g at 0x00000253957B78C8> True
    
    >>> g = lambda x: 3*x
    >>> g.__qualname__ = "g"
    >>> pickle.dumps(g)
    b'\x80\x03c__main__\ng\nq\x00.'