Python Note 2 – OO

This post is an overview of what I’ve learned on Python OO programming.

- Hey, those are private!
- But we are in the same class…

Attribute or method with underscore “_”

_single_leading_underscore

Weak “internal use” indicator.
“from M import *” does not import objects whose name starts with an underscore.

single_trailing_underscore_

used by convention to avoid conflicts with Python keyword, e.g.

Tkinter.Toplevel(master, class_='ClassName')

__double_leading_underscore

Strong “internal use” indicator.
When naming a class attribute, invokes name mangling, e.g.

Foo.__bar --> Foo._Foo__bar

User can create __something outside class definition, but it would be a different attribute.

__double_leading_and_trailing_underscore__

“Magic” objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__.
Some of them correspond to a certain function, e.g. len(a) returns a.__len__
Never invent such names; only use them as documented.
(Retrieved from http://stackoverflow.com/questions/8689964/why-do-some-functions-have-underscores-before-and-after-the-function-name)

Inheritance and polymorphism

  • When we invoke a method, we are always calling the most specific version.
  • When an inherited method invokes some methods, it is also calling the most specific version.
  • Open/closed principle : “Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”
  • Duck typing : As long as what you put in has a .read() method, it is a file-like object.
    NB: Do not give a class attribute and an instance attribute a same name. Because the instance attribute will cover the class attribute and cause confusion.
  • Note that in Python we can inherit from multiple parent classes.
    So we can inherit from MixIn classes to add features to our class.

Get class information

  • Use type(object) or isinstance(obj, class) to determine the relationship between an object and a class.
  • Use dir() to get a directory of all attributes and methods.
  • Use hasattr(obj, "attr_name"[, default]) to check whether such an attribute exists.
  • Use delattr(obj, "attr_name") to delete an attribute.
  • Use setattr(obj, "attr_name") ,getattr(obj, "attr_name") to set and fetch attribute using string, e.g.
import statsout
def output(data,format="text"):
output_function = getattr(statsout, "output_%s" % format)
return output_function(data)

__slots__

  • As a dynamic language, python allow binding attributes and even methods(using types.MethodType(func, instance)) to a certain instance.
  • To restrict attributes that can be added to this class’s instance, use __slots__ = ("attr1", "attr2", ...) in class definition.
    Don’t miss the “s”.
    Whether __slots__ is inherited depends on whether there is another __slots__ in the subclass.
    If there is, then it will. And the __slots__ in the subclass expands the slots.
    If there isn’t, it won’t be inherited and there is no limitation for the subclass.

@property

  • Using getters and setters all the time may be inconvenient.
    We want to directly address an attribute when getting or setting its value, while still be able to monitor whether the input value is valid.
    And we achieve that with the help of the decorators @property and @sth.setter
  • Suppose we have an attribute __width,
class Foo
__width = None

@property
def width(self):
return self.__width

@width.setter
def width(self, value):
if 0 < value <= 60:
self.__width = value
else:
raise ValueError

foo = Foo()
foo.width = 12 # OK
print(foo.width) # print “12”
foo.width = -1 # raise ValueError

 

Customize your class

__init__()

Note that __init__ will not be inherited, we use

def __init__(self):
super(Class_name, self).__init__()

Also note that default arguments in __init__ should be immutable.

__str__() and __repr__()

This allows the instance of our class to support str() and repr() in a customized way.
We often use __repr__ = __str__

__iter__() and __next__()

This creates an iterator class.
In __iter__() we return an iterator object, usually self
In __next__() we do most of the things :
– calculate the next value
– if we need to, raise StopIteration

__getitem__(self, n)

This allows the instance of our class to support indexing.
There are also __setitem__ and __delitem__ to be defined.

__getattr()__

This sets the default response if a nonexistent attribute is called.

__call()__

This makes an instance of our class callable, just like a function.
Any instance, if called, will return the same result, which is defined under __call()__.

Metaclass

Creating a class using type()

an_instance = type('New_class',(object,),dict(method_name=func))

type() takes 3 parameters:
1. class name
2. its parent class(es)
3. a dictionary, keys are attribute or method names, values are objects these names point to

creating a metaclass

class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)

class MyList(list, metaclass=ListMetaclass):
pass

__new__ takes 4 parameters:
cls, short for class, the equivalence for self in metaclass
– the 3 parameters required in type(), see last part

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: