Як отримати повний перелік методів та атрибутів об'єкта?


230
dir(re.compile(pattern)) 

не повертає шаблон як один із елементів списків. А саме він повертає:

['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']

Згідно з посібником, він повинен містити

назви атрибутів об'єкта, назви атрибутів класу та рекурсивно атрибутів базових класів класу.

Це також говорить про те

Список не обов'язково є повним.

Чи є спосіб отримати повний список? Я завжди вважав, що реж повертає повний список, але, мабуть, це не так ...

Також: чи існує спосіб перерахувати лише атрибути? Або лише методи?

Редагувати: це насправді помилка в python -> нібито він виправлений у відділенні 3.0 (а можливо, також у 2.6)


5
використання dir()або перевірка модуля, як правило, це правильний спосіб зробити це. Ви використовували reмодуль лише як приклад чи хочете досягти особливої ​​мети?

1
Ви впевнені, що шаблон справді зберігається як дані, щойно зібрані? У мене склалося враження, що точкою складання шаблону було створення автоматизованих кінцевих станів, необхідних для розбору даного шаблону.
Кайл Странд

@hop не можна реєструвати класи класами? Наприклад, вони можуть зробити своє__dir__()
ytpillai

ytpillai: правильно, але тільки в Python 3. Навіть так, питання полягає в тому, чи підпадав би такий клас під "загальний випадок"

Відповіді:


140

Для повного переліку атрибутів коротка відповідь: ні. Проблема полягає в тому, що атрибути фактично визначаються як аргументи, прийняті getattrвбудованою функцією. Оскільки користувач може повторно реалізувати __getattr__, несподівано дозволяючи будь-який тип атрибутів, немає можливого загального способу створення цього списку. dirФункція повертає ключі в __dict__атрибуті, тобто всі атрибути доступні , якщо __getattr__метод не переопределяется.

Що стосується другого питання, це насправді не має сенсу. Власне, методи - це атрибути, що викликаються, і не більше того. Ви можете хоч і фільтрувати атрибути, що викликаються, і, використовуючи inspectмодуль, визначати методи класу, методи чи функції класу.


1
inpect.getmembers (re.compile (pattern)) також не дає шаблону як члена, тому він, ймовірно, використовує dir внутрішньо ... Це гарно!
Bartosz Radaczyński

Я також міг би використовувати дзвінки, щоб перевірити, чи це методи, але справа не в цьому ... Справа в тому, що я не можу довіряти dir, щоб повернути навіть список атрибутів, які насправді є загальнодоступними ...
Bartosz Radaczyński

2
інспектувати мається на увазі бути "принаймні настільки ж" надійним, як dir (). з іншого боку, re - це дуже складний модуль

Що ви визначаєте під "загальнодоступним"? Якщо ви маєте на увазі "можна отримати доступ", то це є втраченою причиною з наведеної причини. В іншому випадку, 'dir' завжди повертає список атрибутів, доступних із реалізацією за замовчуванням getattr.
PierreBdR

2
dir (my_class) повертає щось інше, ніж my_class .__ dict __. keys (). перший також виводить методи такого класу, як init та doc
JuanPi

58

Ось чому новий __dir__()метод був доданий у python 2.6

побачити:


Я отримую цю помилку: >> dir __ (pyrenderdoc) Traceback (останній дзвінок останній): Файл "<string>", рядок 1, в <module> NameError: ім'я '__dir ' не визначено
Mona Jalal

__dir__ () - це метод на об’єкті, а не функція - будь ласка, прочитайте посилання у відповіді, і це
Moe

Одне вкладиш для друку всіх атрибутів та їх значень:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology

21

Ось практичне доповнення до відповідей PierreBdR та Moe:

  • Для 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__атрибут) .


9

Лише для доповнення:

  1. dir()є найбільш потужним / фундаментальним інструментом. ( Найбільш рекомендовано )
  2. Рішення, крім dir()простого, забезпечують спосіб вирішення результатівdir() .

    Перераховуючи атрибути 2-го рівня чи ні, важливо робити просіювання самостійно, тому що іноді ви можете відсіяти внутрішні параметри з провідними підкресленнями __, але іноді вам може знадобитися __doc__doc-string.

  3. __dir__()і dir()повертає однаковий вміст.
  4. __dict__і dir()різні. __dict__повертає неповний вміст.
  5. ВАЖЛИВО : __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)

    TypeError: дескриптор __dir__з 'object'об'єкта потрібен аргумент

    Автор PyTorch модифікував __dir__()метод на щось, що потребує аргументу. Ця модифікація робить dir()помилкою.

  6. Якщо ви хочете отримати надійну схему для переходу всіх атрибутів об'єкта, пам’ятайте, що кожен пітонічний стандарт може бути замінений і може не дотримуватися , і будь- яка умова може бути ненадійною.


5

Так я це роблю, корисно для простих користувацьких об’єктів, до яких ви постійно додаєте атрибути:

Дано об’єкт, створений за допомогою 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}

список усіх атрибутів у Python 3.x: {key: значення для ключа, значення в obj .__ dict __. items (), якщо не key.startswith ("__")} ['_
progla_fields
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.