GGG205
GGG205

Reputation: 849

Python OOP - explain how does work static with type(self)

I've seen examples of how I can make a static variable in a class. Here is an example:

class A:
    _i = 0

    @property
    def i(self):
        print(type(self)) # <class '__main__.A'>
        return type(self)._i

    @i.setter
    def i(self, val):
        type(self)._i = val

Upvotes: 1

Views: 94

Answers (2)

abarnert
abarnert

Reputation: 365707

How type(self) works

It just returns the type of self. You can call type on any object to get its type:

>>> type(2)
int
>>> class C(object): pass
>>> type(C)
type
>>> c = C()
>>> type(c)
__main__.C

(The output may look slightly different on Python 2 vs. Python 3, or on different Python implementations.)


… and make that variables are static?

Well, first, these aren't static variables, they're class variables. If you don't have any inheritance, there's no difference—but if you do… I'll come back to that.

If you create an instance:

>>> a = A()

… and assign a value to i:

>>> a.i = 3

… it calls the setter for the i property, passing a as the self parameter—just like a normal method call.

So, since self is a, and type(a) is A, then type(self) is also A.

Which means type(self)._i is A._i. In other words, it's the class attribute.


So, why is this a class attribute rather than a static attribute? Well, let's add a subclass:

>>> a = A()
>>> class B(A):
...     _i = 1
>>> b = B()
>>> b.i = 5
>>> A._i
0
>>> B._i
5

Each subclass can have its own _i. And because the setter is setting type(self)._i, when self is b, so type(self) is B, type(self)._i is B._i, not A._i.


What does it < class '__main__.A' > mean in OOP and polymorphism

In Python, everything has a repr, meant for programmers, that gets printed out when you evaluate it at the interactive prompt. It's also used as the str (the thing that gets printed by print) if there's nothing better to use as a human-readable (as in real humans, not us programmers) representation.

In general, a repr is either:

  • A string that could be pasted into your code to produce an equal value, if that makes sense and is possible/reasonable.
  • A string inside <> that includes the type, some kind of identifying information if there is any, and some way to distinguish the object from other instances, otherwise.

For types, what you get inside the angle brackets is the fact that it's a class (that's the class part), and the qualified name (that's the __main__.A part, telling you that it's a class named A defined at the top level of a module named __main__), which is both the useful identifier and the way to distinguish it from other classes.

What does is mean specifically in OOP and polymorphism? I can't think of a good answer to that. Even if Python didn't support polymorphism, even if it didn't have first-class types, __main__.A and __main__.B would still be different objects worthy of distinct names, right?

And if you're wondering what kind of name __main__ is: that's just the name of the special module used to run your top-level script or your interactive interpreter session. If you've ever seen a if __name__ == '__main__': guard, that's exactly what it's testing.

Upvotes: 4

deceze
deceze

Reputation: 522085

type() returns the class that an instance was constructed from. I.e. if you do foo = A() (create a new instance of A and assign it to foo), then type(foo) returns A again. That's what <class '__main__.A'> is, it tells you it's the A class object.

Now all you're doing with type(self)._i is the same as A._i. That _i is an attribute of the class A object, which only exists once. Et voilà, that's all that "static" attributes are.

Upvotes: 1

Related Questions