如何确定函数是否已由“lambda”或“def”声明?

2024-04-26 13:13:36 发布

您现在位置:Python中文网/ 问答频道 /正文

如果我声明两个函数ab

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

我们可以使用__name__,比如:

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

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

但是,由于__name__可能已被修改,因此is_lambda_function不能保证返回正确的结果:

>>> a.__name__ = '<lambda>'
>>> is_lambda_function(a)
True

有没有比__name__属性更可靠的方法?你知道吗


Tags: lambda函数nametrue声明类型returnis
2条回答

我趁机潜入cpython's source看看能不能找到什么,恐怕我不得不附和Serge's answer:你不能。你知道吗

简而言之,这是一个lambda在解释器中的旅程:

  1. 在解析过程中,lambdas就像其他所有表达式一样,are read into expr_ty,这是一个包含每个表达式数据的巨大联合体。你知道吗
  2. 然后将这个expr_ty转换为适当的类型(在本例中是Lambda
  3. 过了一段时间,我们降落到the function that compiles lambdas
  4. 这个函数调用assemble,后者调用makecode,后者初始化PyCodeObject(函数、方法以及lambda都在这里结束)。你知道吗

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

好吧,在python3中你不可能可靠。你知道吗

python2用来定义一系列函数类型。因此,方法、lambda和普通函数都有各自的类型。你知道吗

python3只有一种类型function。使用deflambda声明正则函数确实有不同的副作用:def将名称设置为函数的名称(和限定名),并可以设置docstring,而lambda将名称(和限定名)设置为<lambda>,并将docstring设置为None。但这是可以改变的。。。你知道吗

如果函数是从常规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的函数进行pickle,前提是您为其提供唯一的限定名:

>>> g = lambda x: 3*x
>>> g.__qualname__ = "g"
>>> pickle.dumps(g)
b'\x80\x03c__main__\ng\nq\x00.'

相关问题 更多 >