(One of my summaries of the 2023 Dutch pythonconferentie python meeting in Utrecht, NL).
There’s deep magic in python. Some of it is really hard to understand. Guido van Rossum: “from day one, there was deep magic hiding in some places, designed to quietly help users”. Sebastiaan is going to show us a nice example of python magic: how “self” gets injected into method calls on a class:
class Guitar:
def __init__(self, name):
self.name = name
def play_note(self, note):
print(f"{self.name} plays {note}")
You can instantiate a guitar and call my_guitar.play_note("B")
on it. With
just the note as a parameter. But where is the self
coming from? Somehow
your instance of the Guitar class is magically inserted.
Note: self
is not a magical keyword. You can give it a different name and it
will still work (though your code will be unreadable and people will hate
you).
Everything in python is an object. A class is an object (an instantiation of
Type
). A method inside a class is a regular function object. Plus it is
also added with the name of the function as an attribute to the class (the
namespace of the class).
If you call my_guitar.play_note("B")
, your my_guitar
is just an
object. It does not have the attribute pointing at the function in its
namespace. But it does find the function, as python also looks up attributes
in the class of an object: this is what “self” comes from.
You can see it when you look at the method: Guitar.play_note
says it is a
“function”. my_guitar.play_note
says it is a “bound function”.
The magic that is happening is done with “dunder methods”:
__get__
customizes attribute lookup.
__set__
is for setting attributes.
__delete__
is for deleting.
Functions all have a __get__()
method. When accessed on a class, you’ll
get the function back. When accessed on an instance, it returns
a PyMethod
, which is the function bound to the instance where the
instance is passed as the first argument.
There are some decorators that are related to this:
@classmethod
binds the function to the class, not the instance.
@staticmethod
returns the function as-is, without any binding.
@property
lets you easily customize getters and setters for the
attribute.
These “descriptors” allow you to customize how attributes work.
Book recommendation: “fluent python”.
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):