Есть ли способ узнать, был ли объект функции лямбдой или определением?

Рассмотрим две функции ниже:

def f1():
    return "potato"

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

Если не считать самоанализ исходного кода, есть ли способ определить, что f1 было определением, а f2 — лямбдой?

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

Однако код в вопросе переназначает __name__.

user2357112 supports Monica 04.06.2019 22:45

Обратите внимание, что связанный ответ и комментарий @PeterDeGlopper зависят от того, что вы не сделали того, что сделала последняя строка вашего кода, то есть задавать атрибут __name__ вашей лямбды

G. Anderson 04.06.2019 22:45

Зачем вам это нужно?

chepner 04.06.2019 22:47
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
3
478
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете проверить имя объект кода. В отличие от имени функции, имя объекта кода нельзя переназначить. Имя объекта кода лямбды по-прежнему будет '<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__ переназначением или созданными вручную функциями и объектами кода.

Однако вы можете полностью заменить объект кода.

chepner 04.06.2019 22:49

Возможно, забота о том, был ли function создан с помощью лямбда-выражения или оператора def, является также редкой и странной.

chepner 04.06.2019 22:54

@chepner, возможно, это нормально, если вы полностью замените объект кода, потому что если вы это сделаете, вы просто замените само тело функции, поэтому оно будет отражать, является ли функция, которой он был заменен, функцией или лямбдой.

alkasm 04.06.2019 23:05

@alkasm Нет, нет. Это тот же function объект, но с новым телом. Вы не заменили глобальное пространство имен, замыкания, значения параметров по умолчанию и т. д.

chepner 04.06.2019 23:06

Прохладный. Работает и в Python 2.7.

wim 04.06.2019 23:10

@chepner возможное использование - проверка неанонимных функций lambda (как правило, плохая практика) и изменение их на def? использование flake8, несомненно, было бы проще

Chris_Rands 14.06.2019 11:52

@Chris_Rands Просто выполните текстовый поиск lambda в этом случае. Нет смысла пытаться найти функции, которые изначально были определены с помощью lambda, если вы не видите, где он был изначально определен.

chepner 14.06.2019 14:28

Здесь

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.

cs95 04.06.2019 22:56

Вы можете использовать ast.NodeVisitor для достижения своей цели без жесткого кодирования каких-либо вызовов функций, работая на уровне источников, с его помощью вы можете идентифицировать определения функций ВСЕлямбда, ФункцияDef, АсинкФунктионДеф и распечатать их местоположение, имя и т. д. См. пример кода ниже. :

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 05.06.2019 16:02

@wim Не могу не согласиться, но на самом деле SO по теме ast не так много, поэтому я пытаюсь дать широкий ответ, чтобы помочь пользователям, которым понадобится этот самоанализ и которые столкнутся с этим вопросом в будущем, и отвечая на фактический вопрос в то же время.

Andriy Ivaneyko 05.06.2019 21:23

Другие вопросы по теме