Как найти полное имя в Python: __module__ и __qualname__
Полное имя объекта в Python
Под полным именем (fully qualified name) понимается цепочка имен, однозначно идентифицирующая объект в иерархии модулей, классов и вложенных сущностей. Например, для метода draw класса Circle из модуля shapes полное имя будет shapes.Circle.draw. Знание полного имени помогает при логировании, отладке, сериализации и автоматической генерации документации.
В Python каждый объект, определённый на уровне модуля или класса, хранит служебные атрибуты: __name__, __qualname__ и __module__. Их комбинация и даёт полное квалифицированное имя.
Как получить полное имя функции, метода или класса, включая модуль?
Надёжный способ - соединить атрибуты __module__ и __qualname__ через точку.
def my_func(): pass
class A:
def method(self): pass
class Inner:
def inner_method(self): pass
for obj in (my_func, A.method, A, A.Inner.inner_method):
full_name = f"{obj.__module__}.{obj.__qualname__}"
print(full_name)полное имя python (полное имя в python)
__main__.my_func __main__.A.method __main__.A __main__.A.Inner.inner_method
Python set name (установка имени в python)
Пояснение: __module__ содержит имя модуля (здесь __main__ при запуске скрипта), __qualname__ - полное имя относительно пакета с учётом вложенности классов. Если объект определён во внешнем модуле, __module__ будет соответствующим (например, math.sin).
Типичные проблемы
- Лямбды: у лямбда-функций
__qualname__возвращает'<lambda>', что неинформативно. Решение - при необходимости присвоить лямбде имя черезlambda name: ...или создать обычную функцию. - Декораторы: декоратор без
@functools.wrapsзаменяет атрибуты декорируемой функции на свои. Тогда__qualname__и__module__указывают на обёртку, а не на оригинал. Решение - использоватьfunctools.wraps(original)в декораторе. - Встроенные функции: у некоторых встроенных объектов (
len,print) нет атрибута__module__и__qualname__. Для них полное имя можно получить через__name__(например,'builtins.print'), но явного модуля может не быть.
Как получить полное имя объекта, если он был импортирован и неизвестен его модуль?
Используйте модуль inspect.getmodule(obj) для получения модуля, а затем его атрибут __name__. Комбинируйте с __qualname__.
import inspect
import math
def get_full_name(obj):
module = inspect.getmodule(obj)
if module:
module_name = module.__name__
else:
module_name = 'builtins' if hasattr(obj, '__name__') else 'unknown'
qualname = getattr(obj, '__qualname__', getattr(obj, '__name__', str(obj)))
return f"{module_name}.{qualname}"
print(get_full_name(math.sin))
print(get_full_name(len))math.sin builtins.len
Пояснение: inspect.getmodule ищет модуль по словарю sys.modules, сопоставляя объект с его кодом. Для встроенных функций модуль не находится, поэтому в примере используется запасное значение 'builtins'.
Как получить полное имя экземпляра произвольного класса?
У экземпляра нет атрибутов __qualname__ и __module__. Нужно получить их от его класса через obj.__class__.
class MyClass:
pass
instance = MyClass()
full_name = f"{instance.__class__.__module__}.{instance.__class__.__qualname__}"
print(full_name)__main__.MyClass
Как получить полное имя самого выполняющегося скрипта или текущего модуля?
Воспользуйтесь глобальной переменной __name__ и, если нужно, __file__ для пути.
print("Полное имя модуля:", __name__)
print("Путь к файлу:", __file__)Полное имя модуля: __main__ Путь к файлу: /home/user/script.py
При запуске python -m package.module __name__ будет package.module, а __file__ - абсолютный путь к файлу модуля.
# Пример 1: Рекурсивное получение полного имени для вложенных классов и методов
class Outer:
class Middle:
class Inner:
def method(self): pass
def middle_method(self): pass
def get_full_name_recursive(obj, _cache=None):
if _cache is None:
_cache = {}
qualname = getattr(obj, '__qualname__', None)
module = getattr(obj, '__module__', None)
if qualname and module:
return f"{module}.{qualname}"
# Для экземпляров берем класс
if not hasattr(obj, '__qualname__'):
return get_full_name_recursive(type(obj), _cache)
return str(obj)
outer_inst = Outer()
inner_inst = outer_inst.Middle.Inner()
print(get_full_name_recursive(outer_inst))
print(get_full_name_recursive(inner_inst))
print(get_full_name_recursive(Outer.Middle.Inner.method))
__main__.Outer __main__.Outer.Middle.Inner __main__.Outer.Middle.Inner.method
# Пример 2: Использование inspect.getmembers для вывода всех полных имён в модуле
import inspect
import math
import os
my_module = os
members = inspect.getmembers(my_module, inspect.isfunction)
for name, func in members[:3]: # первые три функции
try:
full = f"{my_module.__name__}.{func.__qualname__}"
print(full)
except AttributeError:
pass
os.abort os.access os.chdir
# Пример 3: Декоратор, сохраняющий полное имя оригинальной функции
import functools
def preserve_fullname(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Вызывается {func.__module__}.{func.__qualname__}")
return func(*args, **kwargs)
# явно копируем атрибуты, хотя @functools.wraps уже это делает
wrapper.__qualname__ = func.__qualname__
wrapper.__module__ = func.__module__
return wrapper
@preserve_fullname
def example(x):
return x * 2
print(example(5))
print("Имя обёртки:", example.__qualname__)
Вызывается __main__.example 10 Имя обёртки: example
# Пример 4: Получение полного имени для объекта, переданного в функцию
import builtins
def full_name_of(obj):
if isinstance(obj, type):
name = getattr(obj, '__qualname__', obj.__name__)
module = getattr(obj, '__module__', 'builtins')
elif hasattr(obj, '__class__'):
name = obj.__class__.__qualname__
module = obj.__class__.__module__
else:
name = type(obj).__name__
module = 'builtins'
return f"{module}.{name}"
print(full_name_of(builtins.int))
print(full_name_of("привет"))
print(full_name_of(42))
builtins.int builtins.str builtins.int
# Пример 5: Сравнение __name__ и __qualname__ для вложенных функций и лямбд
def outer():
def inner():
pass
lam = lambda: None
return inner, lam
inner_func, lam_func = outer()
print("Обычная вложенная:")
print(" __name__:", inner_func.__name__)
print(" __qualname__:", inner_func.__qualname__)
print("Лямбда:")
print(" __name__:", lam_func.__name__)
print(" __qualname__:", lam_func.__qualname__)
Обычная вложенная: __name__: inner __qualname__: outer.<locals>.inner Лямбда: __name__: <lambda> __qualname__: <lambda>
Из примера видно, что __qualname__ для внутренней функции содержит цепочку outer.<locals>.inner, а для лямбды - только <lambda>. Для получения полного имени лямбды с указанием места определения можно использовать inspect.getsource (если доступен) или явно хранить имя.