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
Ответы
Ответ 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.