#python
Как узнать имеет функция или метод тело? То есть не просто def f(): pass
Ответы
Ответ 1
Вот более стабильный способ(inspect.getsourcelines далеко не всегда отрабатывает) import dis def check(function): instructions = dis.get_instructions(function) instr = next(instructions, None) if (instr is None) or (instr.opname != 'LOAD_CONST') or (instr.argrepr != 'None'): return False instr = next(instructions, None) return instr and (instr.opname == 'RETURN_VALUE') Как это работает? У каждой функции есть атрибут __code__ в котором записана байтовая строка опкодов. У пустой функции всего 2 опкода LOAD_CONST(загрузить None в стек) и RETURN_VALUE(вернуть то что в стеке(то есть None)). Мы соответственно и проверяем это.Ответ 2
Воспользоваться методом inspect.getsourcelines и проанализировать содержимое функции: def foo(): pass import inspect lines = inspect.getsourcelines(foo) print(lines) # (['def foo():\n', ' pass\n'], 7) print(lines[0][-1].strip() == 'pass') # TrueОтвет 3
Функция в Питоне всегда что-то делает, так как все функции в Питоне возвращают значение при успешном завершении, поэтому как минимум присутствует код, который возвращает None. Примеры: def f(): pass def f(): '' def f(): return def f(): return None f = lambda: None Все эти функции имеют практически идентичный байт-код на моей версии СPython: >>> import dis >>> dis.dis(f) 2 0 LOAD_CONST 0 (None) 2 RETURN_VALUE (стоит упомянуть, что как наличие байт-кода так и как следствие конкретные результаты, генерируемые dis модулем — это детали реализации выбранной версии CPython. Сам по себе Питон не требует наличия байт-кода). На уровне исходного кода так и на уровне AST эти функции отличаются: >>> import ast >>> def dump_ast(func_source): return ast.dump(ast.parse(func_source, 'exec').body[0]) ... >>> dump_ast("def f(): pass") "FunctionDef(name='f', args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Pass()], decorator_list=[], returns=None, docstring=None)" >>> dump_ast("def f(): ''") "FunctionDef(name='f', args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[], decorator_list=[], returns=None, docstring='')" (отличаются значения body, docstring). Формально, тело функции пустое только во втором случае здесь. Что использовать для определения что такое "пустая функция": исходный код, АСД, байт-код — зависит от вашей задачи. Не все функции определены в чистом Питоне, к примеру, встроенные функции такие как len() могут быть на другом языке определены (Си, Java, RPython -- в зависимости от реализации Питона): >>> import inspect >>> inspect.isbuiltin(f) False >>> inspect.isbuiltin(len) True Или внешние функции: >>> import ctypes >>> libc = ctypes.CDLL(None) >>> libc.printf(b"abc\n") abc 4 >>> inspect.isbuiltin(libc.printf) False Опять таки, считать такие функции "пустыми" или нет — зависит от задачи (разные варианты могут выгодны в разных ситуациях).
Комментариев нет:
Отправить комментарий