Как получить полный список методов и атрибутов объекта?
dir(re.compile(pattern))
не возвращает шаблон как один из элементов списков. А именно это возвращает:
['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']
Согласно инструкции, он должен содержать
имена атрибутов объекта, имена атрибутов его класса и рекурсивные атрибуты базовых классов его класса.
Это также говорит о том, что
Список не обязательно полный.
Есть ли способ получить полный список? Я всегда предполагал, что dir возвращает полный список, но, видимо, это не так...
Также: есть ли способ перечислить только атрибуты? Или только методы?
Изменить: это на самом деле ошибка в Python -> предположительно это исправлено в ветке 3.0 (и, возможно, также в 2.6)
5 ответов
Для полного списка атрибутов, краткий ответ: нет. Проблема в том, что атрибуты фактически определяются как аргументы, принятые getattr
встроенная функция. Как пользователь может переопределить __getattr__
Внезапно разрешая любой вид атрибута, нет никакого общего способа создать этот список. dir
функция возвращает ключи в __dict__
атрибут, т.е. все атрибуты, доступные, если __getattr__
метод не реализован.
По второму вопросу это не имеет смысла. На самом деле, методы являются вызываемыми атрибутами, не более того. Вы можете фильтровать вызываемые атрибуты и, используя inspect
Модуль определения класса методов, методов или функций.
Вот почему новый __dir__()
метод был добавлен в Python 2.6
увидеть:
- http://docs.python.org/whatsnew/2.6.html (прокрутите немного вниз)
- http://bugs.python.org/issue1591665
Вот практическое дополнение к ответам PierreBdR и Мо:
- для Python >= 2.6 и классов нового стиля, dir() кажется достаточным;
- для классов старого стиля мы можем, по крайней мере, сделать то, что делает стандартный модуль для поддержки завершения табуляции: в дополнение к dir()
, Ищу __class__
- а потом пойти на свою __bases__
:
# code borrowed from the rlcompleter module
# tested under Python 2.6 ( sys.version = '2.6.5 (r265:79063, Apr 16 2010, 13:09:56) \n[GCC 4.4.3]' )
# or: from rlcompleter import get_class_members
def get_class_members(klass):
ret = dir(klass)
if hasattr(klass,'__bases__'):
for base in klass.__bases__:
ret = ret + get_class_members(base)
return ret
def uniq( seq ):
""" the 'set()' way ( use dict when there's no set ) """
return list(set(seq))
def get_object_attrs( obj ):
# code borrowed from the rlcompleter module ( see the code for Completer::attr_matches() )
ret = dir( obj )
## if "__builtins__" in ret:
## ret.remove("__builtins__")
if hasattr( obj, '__class__'):
ret.append('__class__')
ret.extend( get_class_members(obj.__class__) )
ret = uniq( ret )
return ret
(Тестовый код и выходные данные для краткости удалены, но в основном для объектов нового стиля мы, похоже, получаем те же результаты для get_object_attrs()
что касается dir()
и для классов старого стиля главное дополнение к dir()
выход, кажется, __class__
атрибут))
Только для дополнения:
dir()
это самый мощный / фундаментальный инструмент. [Наиболее рекомендуется]- Решения кроме
dir()
просто предоставить свой способ борьбы с выходомdir()
,
Перечислять атрибуты 2-го уровня или нет, важно сделать просеивание самостоятельно,
потому что иногда вы можете захотеть отсеять внутренние переменные с подчеркиванием__
но иногда вам может понадобиться__doc__
док-строка. __dir__()
а такжеdir()
возвращает идентичный контент.__dict__
а такжеdir()
разные.__dict__
возвращает неполное содержание.ВАЖНО:
__dir__()
иногда может быть переписан автором для какой-либо цели с помощью функции, значения или типа. Вот пример:\\...\\torchfun.py in traverse(self, mod, search_attributes) 445 if prefix in traversed_mod_names: 446 continue 447 names = dir(m) 448 for name in names: 449 obj = getattr(m,name)
Ошибка типа: дескриптор__dir__
из'object'
объект нуждается в аргументеАвтор pyTorch изменил
__dir__()
метод к чему-то, что требует аргумента. Эта модификация делаетdir()
потерпеть поражение.- Если вы хотите, чтобы надежная схема пересекала все атрибуты объекта, помните, что каждый питонический стандарт может быть переопределен и может не выполняться, а каждое соглашение может быть ненадежным.
Вот как я это делаю, полезно для простых пользовательских объектов, к которым вы продолжаете добавлять атрибуты:
Данный объект создан с obj = type("Obj",(object,),{})
или просто:
class Obj: pass
obj = Obj()
Добавьте некоторые атрибуты:
obj.name = 'gary'
obj.age = 32
затем, чтобы получить словарь только с пользовательскими атрибутами:
{key: value for key, value in obj.__dict__.items() if not key.startswith("__")}
# {'name': 'gary', 'age': 32}