Как выполнить итерацию по атрибутам объекта, определенного с помощью getters или @property?

#python #python-3.x #loops #getter

#python #python-3.x #циклы #getter

Вопрос:

Я знаю, как выполнить итерацию по атрибутам объекта. Но это исключает атрибуты, реализованные с помощью getters / setters или декораторов @property.

Как я могу выполнить итерацию по ним?

 class MyClass:

    def __init__(self):
        self.foo = "bar"

    @property
    def myprop(self):
        return "hello"


my_instance = MyClass()

for i in my_instance.__dict__:
    print("object has attribute %s" % i)
  

Этот небольшой скрипт выводит:

 object has attribute foo
  

Однако я хочу скрипт, который печатает:

 object has attribute foo
object has attribute myprop
  

Ответ №1:

Вы можете использовать dir() для получения всех атрибутов, хотя это будет включать методы, унаследованные от базовых классов, включая все более сложные методы из object:

 class MyClass:

    def __init__(self):
        self.foo = "bar"

    @property
    def myprop(self):
        return "hello"


my_instance = MyClass()

for i in dir(my_instance):
    print("object has attribute %s" % i)
  

С принтами:

 object has attribute __class__
object has attribute __delattr__
object has attribute __dict__
object has attribute __dir__
object has attribute __doc__
object has attribute __eq__
object has attribute __format__
object has attribute __ge__
object has attribute __getattribute__
object has attribute __gt__
object has attribute __hash__
object has attribute __init__
object has attribute __init_subclass__
object has attribute __le__
object has attribute __lt__
object has attribute __module__
object has attribute __ne__
object has attribute __new__
object has attribute __reduce__
object has attribute __reduce_ex__
object has attribute __repr__
object has attribute __setattr__
object has attribute __sizeof__
object has attribute __str__
object has attribute __subclasshook__
object has attribute __weakref__
object has attribute foo
object has attribute myprop
  

Вы можете исключить некоторые из них с помощью операций со строками:

 for i in dir(my_instance):
    if i.startswith("__"):
        continue
    print("object has attribute %s" % i)
  

С принтами:

 object has attribute foo
object has attribute myprop
  

Ответ №2:

Вы можете искать property экземпляры в классе object:

 def get_properties(obj):
    cls = type(obj)
    props = {}
    for k in dir(cls):
        attr = getattr(cls, k)
        # Check that it is a property with a getter
        if isinstance(attr, property) and attr.fget:
            val = attr.fget(obj)
            props[k] = attr.fget(obj)
    return props

class A(object):
    def __init__(self, p):
        self._p = p
    @property
    def p(self):
        return self._p
    p2 = property(fget=lambda self: 2 * self._p)

a = A(1)
a_props = get_properties(a)
print(a_props)
# {'p': 1, 'p2': 2}
  

Комментарии:

1. Кажется, это сложнее.. В чем было бы преимущество вашего решения перед Ned Batchelders way?

2. @FlockoMotion Ну, я точно не утверждаю, что есть «преимущество», скорее просто «альтернативный способ сделать это». Может быть лучше или хуже, в зависимости от того, что вы хотите. Если вы хотите конкретно собрать свойства в объекте (атрибуты, объявленные с помощью property ), то это именно то, что вам нужно. Если вы просто хотите знать все, <something> для чего вы можете сделать obj.<something> , то это ответ Неда (который включает в себя, например, также имена методов).