Подтвердить что ты не робот

Python: Можно ли сделать класс итерабельным, используя стандартный синтаксис?

Я унаследовал проект со многими большими классами, составляющими только объекты класса (целые числа, строки и т.д.). Я хотел бы иметь возможность проверить, присутствует ли атрибут без необходимости вручную определять список атрибутов.

Можно ли сделать сам класс python итерабельным, используя стандартный синтаксис? То есть, я хотел бы иметь возможность перебирать все атрибуты класса с помощью for attr in Foo: (или даже if attr in Foo) без необходимости создания экземпляра класса в первую очередь. Я думаю, что могу сделать это, указав __iter__, но до сих пор я не совсем управлял тем, что искал.

Я достиг некоторых из того, что мне нужно, добавив метод __iter__:

class Foo:
    bar = "bar"
    baz = 1
    @staticmethod
    def __iter__():
        return iter([attr for attr in dir(Foo) if attr[:2] != "__"])

Однако это не совсем выполняет то, что я ищу:

>>> for x in Foo:
...     print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'classobj' object is not iterable

Тем не менее, это работает:

>>> for x in Foo.__iter__():
...     print(x)
bar
baz
4b9b3361

Ответ 1

Добавьте __iter__ в метакласс вместо самого класса (предполагая Python 2.x):

class Foo(object):
    bar = "bar"
    baz = 1
    class __metaclass__(type):
        def __iter__(self):
            for attr in dir(Foo):
                if not attr.startswith("__"):
                    yield attr

Для Python 3.x используйте

class MetaFoo(type):
    def __iter__(self):
        for attr in dir(Foo):
            if not attr.startswith("__"):
                yield attr

class Foo(metaclass=MetaFoo):
    bar = "bar"
    baz = 1

Ответ 2

Вы можете перебирать непокрытые атрибуты класса с помощью for attr in (elem for elem in dir(Foo) if elem[:2] != '__').

Менее ужасный способ заклинания:

def class_iter(Class):
    return (elem for elem in dir(Class) if elem[:2] != '__')

затем

for attr in class_iter(Foo):
    pass

Ответ 3

так мы делаем объект класса итерабельным. предоставить класс с помощью iter и метода next(), вы можете перебирать атрибуты класса или их значения. Вы можете оставить метод next(), если хотите, или можете определить следующий ( ) и вызывать StopIteration при некоторых условиях.

например:

class Book(object):
      def __init__(self,title,author):
          self.title = title
          self.author = author

      def __iter__(self):
          for each in self.__dict__.keys():
              yield self.__getattribute__(each)

>>> book  = Book('The Mill on the Floss','George Eliot')
>>> for each in book: each
...
'George Eliot'
'The Mill on the Floss'

этот класс выполняет итерацию над значением атрибута класса Book. Объект класса можно сделать итерабельным, предоставив ему метод getitem. например:

class BenTen(object):
    def __init__(self, bentenlist):
        self.bentenlist = bentenlist

    def __getitem__(self,index):
        if index <5:
            return self.bentenlist[index]
        else:
            raise IndexError('this is high enough')

>>> bt_obj = BenTen([x for x in range(15)])
>>>for each in bt_obj:each
...
0
1
2
3
4

теперь, когда объект класса BenTen используется во внутреннем цикле, getitem вызывается с успешным более высоким значением индекса, пока он не повысит IndexError.