有没有办法判断一个函数对象是lambda还是def?

时间:2019-06-04 20:37:31

标签: python lambda python-datamodel

请考虑以下两个功能:

def f1():
    return "potato"

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

简短地对原始源代码进行内省,是否有任何方法可以检测到f1是def并且f2是lambda?

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

3 个答案:

答案 0 :(得分:15)

您可以检查代码对象的名称。与函数名称不同,不能重新分配代码对象的名称。 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.FunctionTypetypes.CodeType创建的函数或代码对象。我看不到任何处理__code__重新分配或手动创建的函数和代码对象的好方法。

答案 1 :(得分:-1)

您可以使用ast.NodeVisitor来实现目标,而无需通过在源代码层上进行操作来对任何函数的硬编码,使用它可以标识 ALL Lambda,{{ 3}},FunctionDef函数定义并打印出其位置,名称等。请参见下面的代码示例:

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

答案 2 :(得分:-2)

这里

#include <iostream>

template <typename T> 
constexpr std::size_t doSomething ()
 { return sizeof(T); }

template <typename ... Ts>
constexpr int fakeFunc (Ts const & ...)
 { return 0; }

template <typename ... Ts>
constexpr int doStuff ()
 { return fakeFunc( doSomething<Ts>()... ); }


int main()
 {
   constexpr int a { doStuff<char, short, int, long, long long>() };

   (void)a;
 }

输出

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))