DekGenius.com
[ Team LiB ] Previous Section Next Section

22.1 Python and OOP

Python's implementation of OOP can be summarized by three ideas:


Inheritance

Is based on attribute lookup in Python (in X.name expressions).


Polymorphism

In X.method, the meaning of method depends on the type (class) of X.


Encapsulation

Methods and operators implement behavior; data hiding is a convention by default.

By now, you should have a good feel for what inheritance is all about in Python. We've talked about Python's polymorphism a few times already; it flows from Python's lack of type declarations. Because attributes are always resolved at runtime, objects that implement the same interfaces are interchangeable. Clients don't need to know what sort of object is implementing a method they call.

Encapsulation means packaging in Python—hiding implementation details behind an object's interface; it does not mean enforced privacy, as you'll see in Chapter 23. Encapsulation allows the implementation of an object's interface to be changed, without impacting the users of that object.

22.1.1 Overloading by Call Signatures (or Not)

Some OOP languages also define polymorphism to mean overloading functions based on the type signatures of their arguments. Since there is no type declaration in Python, the concept doesn't really apply; polymorphism in Python is based on object interfaces, not types. For example, you can try to overload methods by their argument lists:

class C:
    def meth(self, x):
        ...
    def meth(self, x, y, z):
        ...

This code will run, but because the def simply assigns an object to a name in the class's scope, the last definition of a method function is the only one retained (it's just as if you say X=1, and then X=2; X will be 2).

Type-based selections can always be coded using the type testing ideas we met in Chapter 7, or the argument list tools in Chapter 13:

class C:
    def meth(self, *args):
        if len(args) == 1:
            ...
        elif type(arg[0]) == int:
            ...

You normally shouldn't do this, though—as described in Chapter 12, write your code to expect an object interface, not a specific datatype. That way, it becomes useful for a broader category of types and applications, now and in the future:

class C:
    def meth(self, x):
        x.operation(  )        # Assume x does the right thing.

It's also generally considered better to use distinct method names for distinct operations, rather than relying on call signatures (no matter what language you code in).

    [ Team LiB ] Previous Section Next Section