Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why `__iter__` does not work when defined as an instance variable?

If I define the __iter__ method as follows, it won't work:

class A:

    def __init__(self):
        self.__iter__ = lambda: iter('text')


for i in A().__iter__():
    print(i)

iter(A())

Result:

t
e
x
t
Traceback (most recent call last):
  File "...\mytest.py", line 10, in <module>
    iter(A())
TypeError: 'A' object is not iterable

As you can see, calling A().__iter__() works, but A() is not iterable.

However if I define __iter__ for the class, then it will work:

class A:

    def __init__(self):

        self.__class__.__iter__ = staticmethod(lambda: iter('text'))
        # or:
        # self.__class__.__iter__ = lambda s: iter('text')


for i in A():
    print(i)

iter(A())

# will print:
# t
# e
# x
# t

Does anyone know why python has been designed like this? i.e. why __iter__ as instance variable does not work? Don't you find it unintuitive?

like image 407
AXO Avatar asked Apr 11 '17 12:04

AXO


People also ask

How do you define an instance variable?

An instance variable is a variable that is specific to a certain object. It is declared within the curly braces of the class but outside of any method. The value of an instance variable can be changed by any method in the class, but it is not accessible from outside the class.

Why is an object often referred to as an instance variable?

An instance variable is a variable which is declared in a class but outside of constructors, methods, or blocks. Instance variables are created when an object is instantiated, and are accessible to all the constructors, methods, or blocks in the class.

Can an object be an instance variable?

An object that is created using a class is said to be an instance of that class. We will sometimes say that the object belongs to the class. The variables that the object contains are called instance variables.

What do instance variables hold?

Instance variables hold values that must be referenced by more than one method, constructor or block, or essential parts of an object's state that must be present throughout the class. Instance variables can be declared at the class level before or after use.


1 Answers

It is done by design. You can find the thorough description here: https://docs.python.org/3/reference/datamodel.html#special-method-lookup

Short answer: the special method must be set on the class object itself in order to be consistently invoked by the interpreter.

Long answer: the idea behind this is to speed up well-known constructions. In your example:

class A:
    def __init__(self):
        self.__iter__ = lambda: iter('text')

How often are you going to write a code like this in real life? So, what Python does - it skips a dictionary lookup of the instance, i.e. iter(A()) simply does not "see" that self.__iter__, which is actually self.__dict__['__iter__'] in this case.

It also skips all the __getattribute__ instance and metaclass lookup gaining a significant speedup.

like image 53
Zaur Nasibov Avatar answered Sep 27 '22 22:09

Zaur Nasibov