【问题标题】:Is there any way to tell if a function object was a lambda or a def?有什么方法可以判断函数对象是 lambda 还是 def?
【发布时间】:2019-10-20 09:43:30
【问题描述】:

考虑以下两个函数:

def f1():
    return "potato"

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

缺乏对原始源代码的反省,有什么方法可以检测到f1 是一个def 而f2 是一个lambda?

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

【问题讨论】:

  • 问题中的代码重新分配了__name__
  • 请注意,链接的答案和@PeterDeGlopper 的评论都取决于您没有完成代码最后一行所做的事情,即设置 __name__ 属性你的 lambda
  • 为什么需要?

标签: python lambda python-datamodel


【解决方案1】:

您可以检查代码对象的名称。与函数的名称不同,代码对象的名称不能重新分配。 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 语句不可能定义代码对象名称为'&lt;lambda&gt;' 的函数。 可以在创建后替换函数的代码对象,但这样做很少见且很奇怪,因此可能不值得处理。同样,这不会处理通过手动调用types.FunctionTypetypes.CodeType 创建的函数或代码对象。我没有看到任何处理 __code__ 重新分配或手动创建的函数和代码对象的好方法。

【讨论】:

  • 不过,您可以完全替换代码对象。
  • 可以说,关心 function 是通过 lambda 表达式还是 def 语句创建的,罕见且奇怪。
  • @chepner 可以说,如果你完全替换代码对象就可以了,因为如果你这样做了,你只是替换了函数体本身,所以它会反映它被替换的函数是否是函数或 lambda。
  • @alkasm 不,你没有。它是相同的 function 对象,但具有新的主体。您还没有替换全局命名空间、闭包、默认参数值等。
  • 酷。也适用于 Python 2.7。
【解决方案2】:

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

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

【讨论】:

  • 这是对原始源代码的自省 - 超出了问题的范围。
  • @wim 不能不同意,但实际上关于 ast 主题的 SO 并没有那么多,所以我试图给出一个广泛的答案,以帮助需要自省并面临这一问题的用户将来的问题并同时回答实际问题。
【解决方案3】:

这里

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

【讨论】:

  • 这实际上是@user2357112 的答案。
猜你喜欢
  • 2017-04-27
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 2021-02-27
  • 2012-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多