TypeError: 'type' object is not iterable - Iterating over object instances

I am working on a project and I would like to make one of my classes iterable. To the best of my knowledge I can do that with using metaclass.

First of all I would like to understand how metaclass works. Therefore I would like to present my own practicing example where I made a Car class. So here I would like to make my Car class objects iterable then I would like to print the names of them in the main function.

The code example is the following:

__author__ = 'mirind4'
class IterableCar(type): def __iter__(self): return iter(self.__name__)
class Car(object): __metaclass__ = IterableCar def __init__(self, name): self.name = name
if __name__=='__main__': car1 = Car('Mercedes') car2 = Car('Toyota') for cars in Car: print (cars.name)

But unfortunately I got an TypeError:

TypeError: 'type' object is not iterable

Would you be so kind as to tell me where I do the mistake in my code? So far I have checked similar problem-questions over this site and internet but I do not know what the problem is. I am using python 3.4. Thanks in advance!

9

3 Answers

As far as I can tell, making a class object iterable by using a metaclass works just fine:

from __future__ import print_function
class IterableCar(type): def __iter__(cls): return iter(cls.__name__)
class Car(object): __metaclass__ = IterableCar def __init__(self, name): self.name = name
if __name__=='__main__': car1 = Car('Mercedes') car2 = Car('Toyota') for cars in Car: print (cars)

Results in:

mgilson$ python ~/sandbox/test.py
C
a
r

Here's an example where I actually track the cars generated:

from __future__ import print_function
import weakref
class IterableCar(type): _cars = weakref.WeakSet() def __iter__(cls): return iter(cls._cars) def add_car(cls, car): cls._cars.add(car)
class Car(object): __metaclass__ = IterableCar def __init__(self, name): self.__class__.add_car(self) self.name = name
if __name__=='__main__': car1 = Car('Mercedes') car2 = Car('Toyota') for cars in Car: print (cars.name)

Note that if you're using python3.x, to use a metaclass you do:

class Car(metaclass=IterableCar): ...

Rather than:

class Car(object): __metaclass__ = IterableCar

which likely explains the problem that you're experiencing.

7

To track instances of the class that are created, we'll start by adding a _cars attribute to each the class created by the metaclass. This will be set of weak references, so that the class itself does not prevent unused instances from being garbage-collected.

class IterableCar(type): def __new__(meta, name, bases, attrs): attrs['_cars'] = weaker.WeakSet() return type.__new__(meta, name, bases, attrs)

To add the instances, we'll override __call__. Essentially, this is where you put code that you would ordinarily put in __new__ or __init__ when defining the class itself.

 def __call__(cls, *args, **kwargs): rv = type.__call__(cls, *args, **kwargs) cls._cars.add(rv) return rv

And to make the class iterable by iterating over its set of instances,

 def __iter__(self): return iter(self._cars)

Any class using IterableCar will automatically track its instances.

class Car(metaclass=IterableCar): def __init__(self, name): self.name = name
car1 = Car('Mercedes')
car2 = Car('Toyota')
for cars in Car: print(cars.name)
3

I had this error appear when a decorator was expecting a Tuple and I passed in a single element without a trailing comma.

@api_view(["GET"])
@authentication_classes((CustomAuthentication,))
@permission_classes((AdminPermission))
def order_attached_documents_from_order_uuid(request): # ... return Response(status=status.HTTP_200_OK)

After I changed @permission_classes((AdminPermission)) to @permission_classes((AdminPermission,)) everything started working just fine.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like