Lecture 4
Classes, objects, inheritance
Problem statement
Your character is Steve.
He has: a name, health, coordinates on the map, an inventory.
How do you program this?
First attempt
One player - works great.
What about 1000 of them?
And there are mobs around. And villages. And animals. Something went wrong.
Better, but not perfect
Better already. But a player has to walk, break blocks, eat food.
Each time - a separate function that takes a dictionary. And what if someone passes the "wrong" dictionary?
Class and object
Programmers are lazy people.
They came up with: let's pack the player's data and what they can do into one box.
This box is called a class.
Concept
A class is a description of how a player is built.
By itself it does nothing.
It is a template from which real players are later made.
Concept
An object is what was born from the blueprint.
One object = one real player with their own name and hp.
From a single blueprint you can make as many objects as you want.
The key idea
Each with its own data. One blueprint.
What an object consists of
These are attributes - data.
These are methods - actions.
All of OOP is about these two words.
What an object consists of
An attribute is a variable "attached" to an object.
Each object has its own attributes.
What an object consists of
A method is a function "attached" to an object.
All objects of the same class can do the same things.
Creating your first class
That's the whole class. Three lines of body.
Syntax
The class name starts with a capital letter. That's a convention.
Constructor
__init__When we tell Python "make a player", it:
Player blueprint__init____init__ - from the word initialize, "to set up".
The self parameter
When we write the blueprint, we don't yet know
what a specific player is called.
self is a pronoun. Inside a class it means "mine, this specific player's".
The self parameter
self is the object's way to reach its own pockets.
Creating the first player
The dot reads as "of": "Steve's name", "Steve's hp".
Multiple objects
One blueprint - two different objects.
Multiple objects
These are two different boxes. Physically different.
Multiple objects
id() - the unique address of an object in memory. is compares by address.
Tens of bytes per object. 1000 players ≈ 50 KB - objects are cheap.
Multiple objects
b = a - not a copy, but a second name for the same box.
Multiple objects
Objects are not linked to one another.
Changing one does not affect the others.
Multiple objects
A thousand players. Each with its own data.
This is what it was all started for.
Class methods
A method is a function inside a class. Its first parameter is always self.
Class methods
A call with the dot. Python supplies self itself.
Under the hood
When you write
Python internally translates it into
steve automatically takes the place of self.
Class methods
In the parentheses there is only amount. Python supplies self itself.
Class methods
A method can return a value - just like an ordinary function.
Class methods
Inside a class, methods freely communicate through self.
Magic method
__str__: controlling print()Without __str__ you would see <__main__.Player object at 0x7f...> - an address in memory.
Double underscores are a convention for "service" methods that Python calls itself.
OOP in the standard libraries
Each dot is a call to a method on an object.
You have been using OOP since the very first lecture, you just didn't call it that.
Example
A string is an object of the str class.
It has an upper method.
It's the same as steve.say(...). The str class was simply written by the Python developers.
Example
df - an object of the DataFrame class.
Methods: head, groupby, describe. Attributes: shape, columns.
Built exactly like our Player - only with hundreds of methods.
Example
LinearRegression - a class. model - an object. fit/predict - methods.
When you understand OOP, you understand how large libraries are built.
Practice #1
name, hp (default 20), inventory (an empty list)pickup(item) - add an item to the inventoryhas(item) - whether the item is present__str__ - <Steve> hp: 20, items: 3Practice #1
The same thing, but from real life:
owner, balance (default 0)deposit(amount), withdraw(amount)Not a game - but built the same way.
Walkthrough
Break
Next: night falls, mobs appear - and we will understand
why we write one method instead of a hundred.
The duplication problem
Mobs come out of the darkness:
moves slowly and hits in melee
shoots a bow from a distance
quietly approaches and explodes
They all have in common: a name, hp, a coordinate, the ability to take damage.
The only difference is how they attack.
The brute-force solution
And the same again for Creeper. Seven lines copied three times.
Why you can't do this
take_damage - you fix it in Zombie, you forget it in SkeletonWe will not do it this way.
Inheritance
The common part - into one parent class.
The unique part - into the children.
Children get the common part automatically.
Inheritance
The common part is gathered in one place.
Inheritance
Zombie(Mob) - "Zombie inherits from Mob". Inside - only the new ability.
What you got for free
We defined only attack, but everything else works.
Extending __init__
super().__init__(name, hp) - "do everything the parent does, and then I'll add my own".
Attention
You overrode __init__ - make super().__init__(...) the first line.
Words
parent, base, superclass
child, descendants, subclasses
The notation Zombie(Mob) reads as: "Zombie is a Mob plus a bit more".
Overriding and polymorphism
The same method name - a different implementation.
Which version to call?
Python looks at the object's type and calls the right version of attack.
Magic in a single loop
The loop doesn't care who is inside. It just calls .attack().
This is exactly what is called polymorphism. The idea is simple: one interface, different behavior.
OOP in real projects
Different models - one interface, fit/predict.
The same loop we had with the mobs.
Also inheritance
ValueError - a kind of Exception.
When you write except Exception - all of them are caught, because of inheritance.
Common mistakes
An attribute is created only through self.name = ...
Common mistakes
You overrode __init__ - make super().__init__(...) the first line.
Common mistakes
Lists and dictionaries - only in __init__, not at the class level.
Practice #2
Without Minecraft - reinforcing the technique on a simple example.
Animal(name) with a method sound() = "..."Dog(Animal) overrides sound() = "Woof"Cat(Animal) overrides sound() = "Meow"describe() in Animal: "{name} says {sound()}"Walkthrough
The same technique as with Zombie/Skeleton/Creeper. The same loop. Just different names.
Summary
self - "mine" inside a class__str__ - controlling how an object is printedsuper() - calling the parentSummary
When you see df.groupby(...) or model.fit(...), you now know how it is built inside.
Closing
Telegram: @gokalqurt