8

考虑以下两个函数:

def f1():
    return "potato"

f2 = lambda: "potato"
f2.__name__ = f2.__qualname__ = "f2"

缺少对原始源代码的反省,有什么方法可以检测到它f1是一个 deff2还是一个 lambda?

>>> black_magic(f1)
"def"
>>> black_magic(f2)
"lambda"
4

3 回答 3

17

您可以检查代码对象的名称。与函数的名称不同,代码对象的名称不能重新分配。lambda 的代码对象的名称仍然是'<lambda>'

>>> x = lambda: 5
>>> x.__name__ = 'foo'
>>> x.__name__
'foo'
>>> x.__code__.co_name
'<lambda>'
>>> x.__code__.co_name = 'foo'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute

语句不可能def定义代码对象名称为 的函数'<lambda>'。可以创建后替换函数的代码对象,但这样做很少见而且很奇怪,可能不值得处理。同样,这不会处理通过手动调用types.FunctionType或创建的函数或代码对象types.CodeType。我看不到任何处理__code__重新分配或手动创建的函数和代码对象的好方法。

于 2019-06-04T20:46:07.690 回答
1

您可以使用ast.NodeVisitor来实现您的目标,而无需通过在源层上操作对函数的任何调用进行硬编码,使用它您可以识别所有 LambdaFunctionDefAsyncFunctionDef函数定义并打印出它的位置、名称等。请参阅代码下面的示例:

import ast


class FunctionsVisitor(ast.NodeVisitor):

    def visit_Lambda(self, node):
        print(type(node).__name__, ', line no:', node.lineno)

    def visit_FunctionDef(self, node):
        print(type(node).__name__, ':', node.name)

    def visit_AsyncFunctionDef(self, node):
        print(type(node).__name__, ':', node.name)

    def visit_Assign(self, node):
        if type(node.value) is ast.Lambda:
            print("Lambda assignment to: {}.".format([target.id for target in node.targets]))
        self.generic_visit(node)

    def visit_ClassDef(self, node):
        # Remove that method to analyse functions visitor and functions in other classes.
        pass

def f1():
    return "potato"

f2 = f3 = lambda: "potato"
f5 = lambda: "potato"

async def f6():
    return "potato"

# Actually you can define ast logic in separate file and process sources file in it.
with open(__file__) as sources:
    tree = ast.parse(sources.read())
    FunctionsVisitor().visit(tree)

以下代码的输出如下:

FunctionDef : f1
Lambda assignment to: ['f2', 'f3'].
Lambda , line no: 27
Lambda assignment to: ['f5'].
Lambda , line no: 28
AsyncFunctionDef : f6
于 2019-06-05T07:52:50.200 回答
-2

这里

def f1():
    return "potato"


f2 = lambda: "potato"


def is_lambda(f):
    return '<lambda>' in str(f.__code__)


print(is_lambda(f1))
print(is_lambda(f2))

输出

False
True
于 2019-06-04T20:54:24.283 回答