有啥方法可以判断函数对象是 lambda 还是 def?
Posted
技术标签:
【中文标题】有啥方法可以判断函数对象是 lambda 还是 def?【英文标题】: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
为什么需要?
【参考方案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
语句不可能定义代码对象名称为'<lambda>'
的函数。 可以在创建后替换函数的代码对象,但这样做很少见且很奇怪,因此可能不值得处理。同样,这不会处理通过手动调用types.FunctionType
或types.CodeType
创建的函数或代码对象。我没有看到任何处理 __code__
重新分配或手动创建的函数和代码对象的好方法。
【讨论】:
不过,您可以完全替换代码对象。 可以说,关心function
是通过 lambda 表达式还是 def
语句创建的,也罕见且奇怪。
@chepner 可以说,如果你完全替换代码对象就可以了,因为如果你这样做了,你只是替换了函数体本身,所以它会反映它被替换的函数是否是函数或 lambda。
@alkasm 不,你没有。它是相同的 function
对象,但具有新的主体。您还没有替换全局命名空间、闭包、默认参数值等。
酷。也适用于 Python 2.7。【参考方案2】:
您可以使用ast.NodeVisitor 来实现您的目标,而无需通过在源层上操作对函数的任何调用进行硬编码,使用它您可以识别ALL Lambda、FunctionDef、@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 的答案。以上是关于有啥方法可以判断函数对象是 lambda 还是 def?的主要内容,如果未能解决你的问题,请参考以下文章
正则表达式、linq表达式、lambda 表达式区别 ,这3者有啥关系和区别么?