Skip to content

Instantly share code, notes, and snippets.

@timbledum
Created March 26, 2019 23:54
Show Gist options
  • Save timbledum/f418ee385f4dce57ce5deaa2e22dd2bf to your computer and use it in GitHub Desktop.
Save timbledum/f418ee385f4dce57ce5deaa2e22dd2bf to your computer and use it in GitHub Desktop.

So you know how you have built in types in python? For example, lists.

list is a type, and we can pretty much create our own custom types by making classes. This is confirmed by Python:

>>> type(list)
<class 'type'>

>>> class Sample:
...     pass
...
>>> type(Sample)
<class 'type'>

We can implement almost all of the things that a list or dict can do with our custom class - the main exception being that we can't create a new instance with special syntax like "hello" or {"key": 5}, we have to use the Sample() constructor.

So a class is the type - or another way of thinking of it is a template or a factory - and the instance is the actual thing.

>>> type(Sample)
<class 'type'>
>>> list  # class
<class 'list'>
>>> "hello"  # instance
'hello'

>>> Sample  #class
<class '__main__.Sample'>
>>> Sample()  # instance
<__main__.Sample object at 0x000001EFFD6D02B0>

Following on from my post above, I wanted to further explore the relationship between the class and the instance.

So we can instiate a class to create an object.

>>> instance = Sample()
>>> instance
<__main__.Sample object at 0x000001EFFD649898>

Cool. Now we have like a blank object that we can do what we like with. Let's add some attributes using dot notation.

>>> instance.x = 5
>>> instance.y = 6
>>> instance.x
5
>>> instance.y
6

Great! We can now easily store and access data, sort of like a dict but a bit easier (but with no funcionality).

We can also add functions to this namespace. Let's add one to multiply x and y together:

>>> instance.xy_product = lambda x, y: x * y

This is fantastic, but has one problem - we still have to manually pass in x and y to make it work:

>>> instance.xy_product(instance.x, instance.y)
30

So python has this nifty feature that if you attach the function at the class level, the function automatically gets passed the object instance if called at the object level. This is when you call it a method rather than a function.

>>> Sample.xy_product = lambda instance: instance.x * instance.y
>>> Sample.xy_product(instance)  #s till have to pass it in manually at the class level
30
>>> instance2 = Sample()
>>> instance2.x = 3
>>> instance2.y = 4
>>> instance2.xy_product()  # but don't have to pass it in at the instance level
12

Of course it's very uncommon to add functions to a class after the fact. Usually this is done at class creation time. We also usually call this instance "self".

class Sample2:
    def xy_product(self):
        return self.x * self.y

Now, it can get pretty cumbersome to manually set x and y like this. It turns out that our blank class has a number of methods already set up by default by python, and we can override them (provide our own implementation of them) to define custom behaviour which is more similar to the built in types. Here's a list of these special methods for our original Sample class - notice that they all look like __name__ so that we don't override them by accident.

>>> dir(Sample)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'xy_product']

One of interest that we can override is __init__ - this gets executed with whatever we pass in when we initiate the class. So now instead of:

>>> instance = Sample()
>>> instance.x = 5
>>> instance.y = 6

We can just do

>>> instance = Sample(5, 6)

Let's do this the hacky way:

>>> def set_up_instance(self, x, y):
...     self.x = x
...     self.y = y
...
>>> Sample.__init__ = set_up_instance
>>> instance3 = Sample(5, 12)
>>> instance3.x
5
>>> instance3.y
12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment