Python Basics: Object-Oriented Programming (Summary)
Now you’re ready to use object-oriented programming (OOP) to write more readable and maintainable code in Python! With OOP, you can create blueprints for objects that contain both data and behaviors.
In this video course, you’ve learned how to:
- Create a
class
- Use classes to create new objects
- Instantiate classes with attributes and methods
To learn more about OOP, check out:
- Object-Oriented Programming (OOP) in Python 3
- Intro to Object-Oriented Programming (OOP) in Python
- Getters and Setters: Manage Attributes in Python
- Operator and Function Overloading in Custom Python Classes
OOP is a big topic, and Real Python has several resources to help you expand your skill set. There’s even a learning path that’ll help you solidly grasp the fundamentals of OOP so that you can make your programs easier to write and maintain.
To reinforce what you’ve learned here, complete the quiz in the next lesson. Then, head over to Python Basics Exercises: Object-Oriented Programming.
Then, keep growing your skill set as a programmer by continuing with the other Python Basics courses and getting yourself a copy of Python Basics: A Practical Introduction to Python 3.
Congratulations, you made it to the end of the course! What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment in the discussion section and let us know.
00:00 So you’re at the end of Object-Oriented Programming. That was a lot of information. And again, you have to practice this stuff for it to really sink in. A lot of it might seem like, what do I use that for?
00:10 Or in what cases is that useful? Can you give me a real-life application for this? And there are loads. You can use it everywhere. But it really won’t start to click until you yourself start using it or reading other people’s code and understanding why they’re using it in this case and how it’s being used. You’ve learned about the object-oriented programming paradigm.
00:32 Now, paradigm is just a fancy word for saying style or way of doing things. You’ve defined a class. You’ve added attributes to that class. You’ve added methods. You’ve used objects created from classes.
00:47 If you’re looking to dive in a bit deeper, Real Python has some additional resources for you to get stuck into. For instance, Object-Oriented Programming (OOP) in Python 3, which is a very in-depth article about everything you want to know about object-oriented programming in Python 3.
01:04 That itself also has another video course that goes into more detail than this one. You have Getters and Setters: Manage Attributes in Python. You’ll have seen how in the class instances in this course, you’ve been referencing attributes and setting attributes with dot notation and assignment directly, but the getting and setting of these attributes is a big topic.
01:27 If you’re curious about more of that and how to customize the behavior of that—maybe every time you get an attribute, you want something to happen. More likely, it is when you set an attribute you want something to happen.
01:38
Maybe it needs to update other attributes. Check out that article. And finally, we’ve got Operator and Function Overloading in Custom Python Classes. Now, this is the dunder methods we are talking about, where you can customize how your instances behave with certain operators, like +
(addition), -
(subtraction), ==
(equals to), >
(greater than), <
(less than). Now, Real Python’s content on object-oriented programming, classes, and instances is not limited to these three, but is a huge subject.
02:12 And that was an introduction to object-oriented programming. Thank you for watching and following along.
Martin Breuss RP Team on July 20, 2023
@risko619 aah, yes OOP is a complex programming topic that can totally take a while to sink in. Best thing to do is to keep reading or watching content that covers it, and just mess around trying to solve the challenges. Even if you don’t get it all the way, putting in some practice time and (figuratively) banging your head against that OOP wall helps to make it click eventually.
Is there anything specific that you got stuck with? Did you check out the other resources that Ian mentioned in this lesson?
Sneha Nath on Sept. 16, 2023
Excellent course and very informative! Thank you so much.
alphafox28js on Nov. 19, 2023
I wish they would have explaned how to print all the functions of the class at with one iteration…
class Dog:
species = "Canis Familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return (f"{self.name}, {self.age}")
Pepper = Dog('Pepper',4)
# Instance Method:
def description(self):
return (f"{self.name} is {self.age} years old, and she is the greatest dog alive!")
Pepper.description()
def speak(self, sound):
return f"{self.name} says {sound}"
Pepper.speak()
Pepper = Dog('Pepper',4)
Pepper.description()
Pepper.speak('Woof! Woof!')
Martin Breuss RP Team on Nov. 22, 2023
I’m not sure I correctly understood your question, but generally, you can inspect a Python object using dir()
.
That gives you everything though, so you might want to filter the results, e.g. like shown below if you’re only looking for instance methods you defined in the class:
print(
[
method
for method in dir(Pepper)
if callable(getattr(Pepper, method))
and not method.startswith("__")
]
)
When you run this code on the Pepper
object you created above, then you’ll get the two instance method names as a result:
['description', 'speak']
Alternatively, you could also look into the built-in inspect
module.
Did this answer your question, or did you mean something else?
alphafox28js on Nov. 23, 2023
Good Morning @Martin Breuss… So basically, when trying to instantiate the Attributes of the class via Instances. I keep running into a problem when separting Main_Class vs SubClass vs code variable assignments.
example. would be something like this… New Window_Script 1: Main_Class
class Animal:
species = "Mammals"
def __init__(self, name, age): #type: [Canine. breed: breed of canine, internal_temp: warm/cold blooded.]
self.name = name
self.age = age
# Instance Methods:
def __str__(self):
return f"{self.name} is {self.age} years old."
def speak(self, sound):
return f"Sound of {self.name}; {sound}."
class Pitbull(Animal):
def speak(self, sound = "GgggrrrWOOF!"):
return f"{self.name} says {sound}."
class Shephard(Animal):
pass
class Doberman(Animal):
pass
New Window_Script 2: Subscript_Class
from P_Class_Animal import Animal
class Pitbull(Animal):
def speak(self, sound= "ggggrrrWoooF!"):
return f"{self.name} says {sound}"
class Shephard(Animal):
pass
class Doberman(Animal):
pass
New Window_Script 3: Variables of Animial Classes
from P_Class_Animal import Animal
from C_Class_Animal import Animal, Pitbull
#instantiate Parent Class
Dog = Animal('Wolf', 2)
print(Dog)
#instantiate child/sub classes which points to the breed
Athena = Pitbull('Athena', 3,)
Athena.speak()
print(Athena)
While I was able to get the above working (to a point), still will not let me call .species(), the problem comes when I try to essentially create a dictionary for the Animal Class and define Multiple Types of Dogs in the Child Class with a variety of attributes
alphafox28js on Nov. 23, 2023
Now,lets say I added the following, and if i were to instantiate lets say Pitbull as follows, it has yet to function properly, not sure how to correct. New_Window P_Class
class Animal:
def __init__(self, name, age, height, coat): #type: [Canine. breed: breed of canine, internal_temp: warm/cold blooded.]
self.name = name
self.age = age
self.height = height
self.coat = coat
# Instance Methods:
def __str__(self):
return f"{self.name} is {self.age} years old."
def speak(self, sound):
return f"Sound of {self.name}; {sound}."
New_Window C_Class
from P_Class_Animal import Animal
class Pitbull(Animal):
def speak(self, sound= "ggggrrrWoooF!"):
return f"{self.name} says {sound}"
def height(self):
return super().height()
class Shephard(Animal):
pass
class Doberman(Animal):
pass
New_Window Animal Variables:
from P_Class_Animal import Animal
from C_Class_Animal import Animal, Pitbull
#instantiate Parent Class
Dog = Animal('Wolf', 2)
print(Dog)
#instantiate child/sub classes which points to the breed
Pitbull = Pitbull('Pitbull', 3,)
Pitbull.speak()
Pitbull.height()
print(Pitbull)
This returns the error of: TypeError. Wanting me to instantiate two more positional arguments. In my mind, this should not be the case because they were defined in the P_Class…What am I missing here?
TypeError: Animal.__init__() missing 2 required positional arguments: 'height' and 'coat'
Even adding the two additional arguments, it still returns TypeError
from P_Class_Animal import Animal
from C_Class_Animal import Animal, Pitbull
#instantiate Parent Class
Dog = Animal('Wolf', 2)
print(Dog)
#instantiate child/sub classes which points to the breed
Pitbull = Pitbull('Pitbull', 3, ".5m", 'Short')
Pitbull.speak()
Pitbull.height()
print(Pitbull)
alphafox28js on Nov. 23, 2023
BTW, Thank You for the Help and Support on this. I truly appreciate it! Also worth noting, I had to add path support to JSON to get the above to work in VS Code via Python.
settings.json
{
"python.analysis.extraPaths": [
"C:/Program Files (x86)/Google/google_appengine",
"C:/Program Files (x86)/Google/google_appengine/lib/flask-0.12"]
}
{
"python.analysis.extraPaths": ["PYTHONPATH": "${workspaceFolder/../extern"]
}
launch.json
{
"configurations": [
{
"name": "Python: File",
"type": "python",
"request": "launch",
"program": "${file}",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder/../extern"
}
},
{
"name": "Python: File",
"type": "python",
"request": "launch",
"program": "${file}",
"justMyCode": true
}
]
}
Hopefully someone down the line will find this useful :)
Martin Breuss RP Team on Dec. 12, 2023
@alphafox28js you probably figured this out at this point, but let me try to recap a few points, maybe it’s helpful for you or someone else reading over this.
Naming Conventions
According to PEP 8, the naming convention for modules and packages is to:
use a short, lowercase word or words. Separate words with underscores to improve readability.
Currently, you’ve used uppercase words for your module (=file) names, which is uncommon. It doesn’t break anything, but it’ll make your code look more professional when you stick to the naming convention.
Overwriting Names
In your first comment, you’re showing the same names multiple times in different files (if I understand your text correctly).
For example, you’re defining Pitbull
multiple times in different files:
- In a file that you probably called
P_Class_Animal.py
- In a file that you probably called
C_Class_Animal.py
In the third file, you also double up your import of the Animal
class, which won’t have an effect:
from P_Class_Animal import Animal
from C_Class_Animal import Animal, Pitbull
The second import of Animal
will overwrite the name, which renders the first line unnecessary.
Note: This won’t make any troubles in the code you’re showing. You’re importing Animal
from P_Class_Animal
in C_Class_Animal
, so the Animal
object you’re referencing twice in this third file is actually the same object.
However, it makes your code harder to read and reason about. It’s always better to cut it down to the essentials, which will help you to avoid bugs and make it more straightforward to keep track of what’s going on in your code.
You always just need to define any name you want to use once. If you define it in a different module, then you can import it into another module where you want to use it.
Instantiation
The TypeError
about missing positional arguments is a result that you’re not passing the required amount of arguments when you’re instantiating an object from your class.
You’ve defined that an Animal
requires four positional arguments:
class Animal:
def __init__(self, name, age, height, coat):
self.name = name
self.age = age
self.height = height
self.coat = coat
Later, you create a child class that inherits from Animal
:
class Pitbull(Animal):
pass # More on the code here a bit later
Inheriting from a parent class (without overwriting the initializer) means that your child class will need as many arguments as the parent class—in this case that’s four.
Therefore, when you attempt to initialize either an Animal
or a Pitbull
object with only two arguments, you’ll get the mentioned error:
>>> Dog = Animal('Wolf', 2)
TypeError: Animal.__init__() missing 2 required positional arguments: 'height' and 'coat'
>>> Pitbull = Pitbull('Pitbull', 3)
TypeError: Animal.__init__() missing 2 required positional arguments: 'height' and 'coat'
You can see from the error messages that Pitbull
is also calling .__init__()
of Animal
.
You mention:
In my mind, this should not be the case because they were defined in the P_Class…What am I missing here?
You only defined the method signature of the Animal
class’ .__init__()
, where you define that it needs to have four positional arguments.
When you go to call that method, which you do by instantiating an object of either class, then you also need to provide values for these required arguments. Does that clarify the situation?
So… given the info above, do you understand why the code in your last code example still returns the same TypeError
:
from P_Class_Animal import Animal
from C_Class_Animal import Animal, Pitbull
#instantiate Parent Class
Dog = Animal('Wolf', 2)
print(Dog)
#instantiate child/sub classes which points to the breed
Pitbull = Pitbull('Pitbull', 3, ".5m", 'Short')
Pitbull.speak()
Pitbull.height()
print(Pitbull)
Let me know :)
Method vs Argument
Finally, there’s another bug in your code that you may or may not have encountered, and it’s hiding in your definition of the Pitbull
child class:
class Pitbull(Animal):
def speak(self, sound= "ggggrrrWoooF!"):
return f"{self.name} says {sound}"
def height(self):
return super().height()
Currently, you’re using Python’s super()
to call a .height()
method from the parent Animal
class.
However, in the code you provided, you never defined such a method. You wrote an initializer function that collects a value for .height
, but that value won’t be callable. It’s an instance attribute and not an method.
So, even if you correctly initialize a Pitbull
object, when you’ll try to call .height()
on it, you’ll get another error:
>>> Pitbull = Pitbull('Pitbull', 3, ".5m", 'Short')
>>> Pitbull.speak()
'Pitbull says ggggrrrWoooF!'
>>> Pitbull.height()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
If you want, you can give it a try to explain to me what’s happening here. :)
Ok that’s it, nice work going through this course in such depth and thinking about the concepts covered. Best way to learn is to think, try, and talk about it! :D
Become a Member to join the conversation.
risko619 on July 19, 2023
I really didnt understand this, nor was I able to run the exercise. Feeling a bit overwhelmed with all this stuff now