|
| https://realpython.com/ |
| Start Here | https://realpython.com/start-here/ |
|
Learn Python
| https://realpython.com/lessons/python-class-creation/ |
| Python Tutorials →In-depth articles and video courses | https://realpython.com/search?kind=article&kind=course&order=newest |
| Learning Paths →Guided study plans for accelerated learning | https://realpython.com/learning-paths/ |
| Quizzes & Exercises →Check your learning progress | https://realpython.com/quizzes/ |
| Browse Topics →Focus on a specific area or skill level | https://realpython.com/tutorials/all/ |
| Community Chat →Learn with other Pythonistas | https://realpython.com/community/ |
| Office Hours →Live Q&A calls with Python experts | https://realpython.com/office-hours/ |
| Podcast →Hear what’s new in the world of Python | https://realpython.com/podcasts/rpp/ |
| Books →Round out your knowledge and learn offline | https://realpython.com/products/books/ |
| Reference →Concise definitions for common Python terms | https://realpython.com/ref/ |
| Code Mentor →BetaPersonalized code assistance & learning tools | https://realpython.com/mentor/ |
| Unlock All Content → | https://realpython.com/account/join/ |
|
More
| https://realpython.com/lessons/python-class-creation/ |
| Learner Stories | https://realpython.com/learner-stories/ |
| Python Newsletter | https://realpython.com/newsletter/ |
| Python Job Board | https://www.pythonjobshq.com |
| Meet the Team | https://realpython.com/team/ |
| Become a Tutorial Writer | https://realpython.com/write-for-us/ |
| Become a Video Instructor | https://realpython.com/become-an-instructor/ |
| Search | https://realpython.com/search |
| https://realpython.com/search |
| Join | https://realpython.com/account/join/ |
| Sign‑In | https://realpython.com/account/login/?next=%2Flessons%2Fpython-class-creation%2F |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=python-class-object |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=python-class-object |
| https://realpython.com/courses/python-class-object/#team |
| Class Concepts: Object-Oriented Programming in Python | https://realpython.com/courses/python-class-object/ |
| Christopher Trudeau | https://realpython.com/courses/python-class-object/#team |
| Recommended Tutorial | https://realpython.com/python-classes/ |
| Course Slides (.pdf) | https://realpython.com/courses/python-class-object/downloads/python-class-object-slides/ |
| Sample Code (.zip) | https://realpython.com/courses/python-class-object/downloads/python-class-object-code/ |
| Ask a Question | https://realpython.com/lessons/python-class-creation/#discussion |
| https://realpython.com/feedback/survey/course/python-class-object/liked/?from=lesson-title |
| https://realpython.com/feedback/survey/course/python-class-object/disliked/?from=lesson-title |
| Transcript | https://realpython.com/lessons/python-class-creation/#transcript |
| Discussion (2) | https://realpython.com/lessons/python-class-creation/#discussion |
| 00:00 | https://realpython.com/lessons/python-class-creation/#t=0.54 |
| In the previous lesson, I explained why you might want to write object-oriented | https://realpython.com/lessons/python-class-creation/#t=0.54 |
| code. In this lesson, I’ll introduce you to how to do just that in Python. | https://realpython.com/lessons/python-class-creation/#t=4.35 |
| 00:10 | https://realpython.com/lessons/python-class-creation/#t=10.61 |
| You saw the PosixPath class and how to instantiate it into an object in the | https://realpython.com/lessons/python-class-creation/#t=10.61 |
| lesson prior to this. | https://realpython.com/lessons/python-class-creation/#t=15.23 |
| That instantiation process is done by calling the class with parentheses. | https://realpython.com/lessons/python-class-creation/#t=16.94 |
| 00:22 | https://realpython.com/lessons/python-class-creation/#t=22.03 |
| The constructor call can take arguments, | https://realpython.com/lessons/python-class-creation/#t=22.03 |
| which most often are the initial values for attributes that you want to keep in | https://realpython.com/lessons/python-class-creation/#t=24.3 |
| the object. Python uses a special method called .__init__(), | https://realpython.com/lessons/python-class-creation/#t=28.65 |
| which it calls as part of the class instantiation process. | https://realpython.com/lessons/python-class-creation/#t=33.06 |
| 00:37 | https://realpython.com/lessons/python-class-creation/#t=37.07 |
| You may hear programmers refer to this as the constructor. That isn’t | https://realpython.com/lessons/python-class-creation/#t=37.07 |
| technically correct, | https://realpython.com/lessons/python-class-creation/#t=41.69 |
| but it’s similar enough to constructors in other languages that it isn’t really | https://realpython.com/lessons/python-class-creation/#t=42.95 |
| worth debating. When you write your own class, | https://realpython.com/lessons/python-class-creation/#t=46.69 |
| you likely are going to need to write a .__init__() method to set it up. | https://realpython.com/lessons/python-class-creation/#t=49.91 |
| 00:54 | https://realpython.com/lessons/python-class-creation/#t=54.61 |
| All of an object’s methods, including .__init__(), | https://realpython.com/lessons/python-class-creation/#t=54.61 |
| automatically get called with a reference to the object as their first argument. | https://realpython.com/lessons/python-class-creation/#t=57.51 |
| When you declare a method, | https://realpython.com/lessons/python-class-creation/#t=63.06 |
| you have to include this argument in the signature. By convention, in Python, | https://realpython.com/lessons/python-class-creation/#t=64.37 |
| this is known as self. Technically, you can call it anything you want. | https://realpython.com/lessons/python-class-creation/#t=69.7 |
| 01:13 | https://realpython.com/lessons/python-class-creation/#t=73.93 |
| The compiler doesn’t enforce the name, | https://realpython.com/lessons/python-class-creation/#t=73.93 |
| but your fellow programmers may beat you, enforcing the convention through a | https://realpython.com/lessons/python-class-creation/#t=76.65 |
| different kind of argument. | https://realpython.com/lessons/python-class-creation/#t=81.23 |
| Let’s go revisit our circle from the previous lesson, this time as a class. | https://realpython.com/lessons/python-class-creation/#t=83.36 |
| 01:30 | https://realpython.com/lessons/python-class-creation/#t=90.84 |
| Logically enough, to declare a class, you use the class keyword. | https://realpython.com/lessons/python-class-creation/#t=90.84 |
| Here I have declared a class called Circle. | https://realpython.com/lessons/python-class-creation/#t=95.2 |
| The colon declares a block, and like with other blocks in Python, | https://realpython.com/lessons/python-class-creation/#t=98.47 |
| everything indented under here is part of the declaration. | https://realpython.com/lessons/python-class-creation/#t=102.02 |
| 01:50 | https://realpython.com/lessons/python-class-creation/#t=110.57 |
| By convention, | https://realpython.com/lessons/python-class-creation/#t=110.57 |
| the initialization method, .__init__(), is typically included first. | https://realpython.com/lessons/python-class-creation/#t=111.37 |
| As you can see here, the first argument to the method, | https://realpython.com/lessons/python-class-creation/#t=116.17 |
| like all methods, is self. When it’s called, | https://realpython.com/lessons/python-class-creation/#t=119.46 |
| it will contain a reference to the object. | https://realpython.com/lessons/python-class-creation/#t=123.41 |
| 02:06 | https://realpython.com/lessons/python-class-creation/#t=126.71 |
| Remember when I said .__init__() strictly isn’t a constructor? | https://realpython.com/lessons/python-class-creation/#t=126.71 |
| This is why. When this method is called, the object has actually already been | https://realpython.com/lessons/python-class-creation/#t=130.14 |
| constructed. It’s being passed into the .__init__() to be initialized by you. | https://realpython.com/lessons/python-class-creation/#t=134.75 |
| 02:20 | https://realpython.com/lessons/python-class-creation/#t=140.22 |
| This is also why .__init__() doesn’t have to return anything. | https://realpython.com/lessons/python-class-creation/#t=140.22 |
| The object already exists, and you can do anything to it when it’s passed in as | https://realpython.com/lessons/python-class-creation/#t=143.93 |
| self. A true constructor in the strictest sense actually has to return the newly | https://realpython.com/lessons/python-class-creation/#t=148.7 |
| constructed object. The second argument here to .__init__() | https://realpython.com/lessons/python-class-creation/#t=153.67 |
| is specific to my Circle class, and it’s the radius of the circle. | https://realpython.com/lessons/python-class-creation/#t=157.27 |
| 02:45 | https://realpython.com/lessons/python-class-creation/#t=165.27 |
| Note that the argument being passed into the initializer doesn’t mean it’s part | https://realpython.com/lessons/python-class-creation/#t=165.27 |
| of the object. To do that, you have to actually assign it to the object. | https://realpython.com/lessons/python-class-creation/#t=169.44 |
| 02:53 | https://realpython.com/lessons/python-class-creation/#t=173.98 |
| As self is a reference to the object being initialized, | https://realpython.com/lessons/python-class-creation/#t=173.98 |
| you use dot notation to store it. | https://realpython.com/lessons/python-class-creation/#t=177.34 |
| I’ve gone with the typical pattern of naming the object attribute the same thing | https://realpython.com/lessons/python-class-creation/#t=179.99 |
| as that passed into the method, but there’s no requirement to do this. | https://realpython.com/lessons/python-class-creation/#t=184.1 |
| 03:08 | https://realpython.com/lessons/python-class-creation/#t=188.63 |
| This little chunk of boilerplate code actually kind of annoys me. | https://realpython.com/lessons/python-class-creation/#t=188.63 |
| Pretty much every single class you write is going to have this, | https://realpython.com/lessons/python-class-creation/#t=192.34 |
| and if you’ve got several arguments, | https://realpython.com/lessons/python-class-creation/#t=195.46 |
| you can have several lines of code devoted to this. | https://realpython.com/lessons/python-class-creation/#t=197.02 |
| 03:20 | https://realpython.com/lessons/python-class-creation/#t=200.36 |
| I feel like there should be an easier way to do this, | https://realpython.com/lessons/python-class-creation/#t=200.36 |
| but don’t quite know what it would look like. This isn’t just a Python thing. | https://realpython.com/lessons/python-class-creation/#t=202.5 |
| Most object-oriented languages have a similar setup. | https://realpython.com/lessons/python-class-creation/#t=206.75 |
| 03:31 | https://realpython.com/lessons/python-class-creation/#t=211.06 |
| So, that’s .__init__(). How about another method? | https://realpython.com/lessons/python-class-creation/#t=211.06 |
| 03:36 | https://realpython.com/lessons/python-class-creation/#t=216.31 |
| Pardon the lack of spacing here. | https://realpython.com/lessons/python-class-creation/#t=216.31 |
| Normally, you put an empty line between methods, | https://realpython.com/lessons/python-class-creation/#t=218.45 |
| but in the REPL, you can’t do that. | https://realpython.com/lessons/python-class-creation/#t=220.47 |
| This line is the declaration of a method called .area(). | https://realpython.com/lessons/python-class-creation/#t=223.08 |
| 03:47 | https://realpython.com/lessons/python-class-creation/#t=227.04 |
| Like all methods in a class, it takes the self argument, and in this case, | https://realpython.com/lessons/python-class-creation/#t=227.04 |
| no others. The | https://realpython.com/lessons/python-class-creation/#t=231.59 |
| 03:57 | https://realpython.com/lessons/python-class-creation/#t=237.73 |
| code for .area() implements the famous πr² formula. | https://realpython.com/lessons/python-class-creation/#t=237.73 |
| Notice how it is accessing the radius stored on the object using self.radius. | https://realpython.com/lessons/python-class-creation/#t=241.99 |
| 04:07 | https://realpython.com/lessons/python-class-creation/#t=247.78 |
| Again, | https://realpython.com/lessons/python-class-creation/#t=247.78 |
| this is possible because self is being passed into the method and is the object. | https://realpython.com/lessons/python-class-creation/#t=248.16 |
| That’s enough for your first class. Let’s use it to create a circle object. | https://realpython.com/lessons/python-class-creation/#t=253.83 |
| 04:21 | https://realpython.com/lessons/python-class-creation/#t=261.5 |
| By using parentheses on the class, | https://realpython.com/lessons/python-class-creation/#t=261.5 |
| I’m calling it. Calling the class constructs an object. Because .__init__() took | https://realpython.com/lessons/python-class-creation/#t=263.42 |
| one argument in addition to self, the constructor here expects a value. | https://realpython.com/lessons/python-class-creation/#t=268.36 |
| 04:33 | https://realpython.com/lessons/python-class-creation/#t=273.06 |
| If I hadn’t put the 3 in this code, I’d get an error. | https://realpython.com/lessons/python-class-creation/#t=273.06 |
| As I did put 3, it gets passed into the constructed object, | https://realpython.com/lessons/python-class-creation/#t=277.06 |
| which then calls .__init__(), | https://realpython.com/lessons/python-class-creation/#t=280.97 |
| passing the argument along. The .__init__() then stores the 3 | https://realpython.com/lessons/python-class-creation/#t=282.75 |
| in the self.radius attribute. Once .__init__() is done, | https://realpython.com/lessons/python-class-creation/#t=287.58 |
| the constructor returns the new object, | https://realpython.com/lessons/python-class-creation/#t=291.86 |
| which I’ve stored in the variable named small. | https://realpython.com/lessons/python-class-creation/#t=293.73 |
| 04:59 | https://realpython.com/lessons/python-class-creation/#t=299.32 |
| I can access the attributes on the object by using dot notation, | https://realpython.com/lessons/python-class-creation/#t=299.32 |
| 05:05 | https://realpython.com/lessons/python-class-creation/#t=305.82 |
| and similar for calling a method. | https://realpython.com/lessons/python-class-creation/#t=305.82 |
| Note that self isn’t used in the invocation of this method. | https://realpython.com/lessons/python-class-creation/#t=308.31 |
| Calling a method on an object automatically passes the object to the method. | https://realpython.com/lessons/python-class-creation/#t=312.23 |
| 05:16 | https://realpython.com/lessons/python-class-creation/#t=316.82 |
| As the .area() method doesn’t take any other arguments, | https://realpython.com/lessons/python-class-creation/#t=316.82 |
| it is invoked without any at all. Let’s create another circle. | https://realpython.com/lessons/python-class-creation/#t=319.78 |
| 05:26 | https://realpython.com/lessons/python-class-creation/#t=326.7 |
| This time, the radius is a bit bigger, | https://realpython.com/lessons/python-class-creation/#t=326.7 |
| 05:30 | https://realpython.com/lessons/python-class-creation/#t=330.32 |
| and you can see its attribute. | https://realpython.com/lessons/python-class-creation/#t=330.32 |
| 05:34 | https://realpython.com/lessons/python-class-creation/#t=334.28 |
| And of course, I can calculate the area on this one as well. | https://realpython.com/lessons/python-class-creation/#t=334.28 |
| Attributes are also editable | https://realpython.com/lessons/python-class-creation/#t=338.61 |
| 05:43 | https://realpython.com/lessons/python-class-creation/#t=343.44 |
| Here, I’ve set the radius to a new value. When I recall .area(), | https://realpython.com/lessons/python-class-creation/#t=343.44 |
| 05:49 | https://realpython.com/lessons/python-class-creation/#t=349.83 |
| a new result is calculated. | https://realpython.com/lessons/python-class-creation/#t=349.83 |
| Similar to the whole self thing, | https://realpython.com/lessons/python-class-creation/#t=353.24 |
| the style you use when you write a class isn’t enforced by the compiler, | https://realpython.com/lessons/python-class-creation/#t=355.95 |
| but it is best to stick with known practices. | https://realpython.com/lessons/python-class-creation/#t=359.82 |
| 06:02 | https://realpython.com/lessons/python-class-creation/#t=362.91 |
| It’s easier for someone else to understand your code if you use the conventions | https://realpython.com/lessons/python-class-creation/#t=362.91 |
| that everyone else does. First off, like variables, | https://realpython.com/lessons/python-class-creation/#t=366.76 |
| attributes on an object use snake case. That’s all lowercase, with | https://realpython.com/lessons/python-class-creation/#t=370.64 |
| words separated by underscores. Class names themselves use | https://realpython.com/lessons/python-class-creation/#t=375.68 |
| pascal case. That’s no underscores, but with capitals on each word. | https://realpython.com/lessons/python-class-creation/#t=380.34 |
| 06:25 | https://realpython.com/lessons/python-class-creation/#t=385.3 |
| If you’re coming from other object-oriented languages, | https://realpython.com/lessons/python-class-creation/#t=385.3 |
| you might be wondering about things like private, protected, and public permission | https://realpython.com/lessons/python-class-creation/#t=387.78 |
| structures. If you’re not coming from other languages, | https://realpython.com/lessons/python-class-creation/#t=391.76 |
| these concepts control who can see the attribute or call a method— | https://realpython.com/lessons/python-class-creation/#t=394.81 |
| the object, inheritors, or anyone. Python doesn’t really have this concept. | https://realpython.com/lessons/python-class-creation/#t=399.46 |
| 06:44 | https://realpython.com/lessons/python-class-creation/#t=404.7 |
| It uses a suggested convention based on naming instead. | https://realpython.com/lessons/python-class-creation/#t=404.7 |
| If you are coming from another language, this might seem like a bit of a shock. | https://realpython.com/lessons/python-class-creation/#t=408.38 |
| It took me a little to adjust the idea as well. | https://realpython.com/lessons/python-class-creation/#t=412.5 |
| 06:55 | https://realpython.com/lessons/python-class-creation/#t=415.24 |
| I used to write code where I tried my best to protect programmers from | https://realpython.com/lessons/python-class-creation/#t=415.24 |
| themselves, trying to stop them from doing things they weren’t supposed to. | https://realpython.com/lessons/python-class-creation/#t=418.24 |
| Python’s attitude is a little more permissive. It essentially says, Hey, | https://realpython.com/lessons/python-class-creation/#t=422.4 |
| this is dangerous, but if you know what you’re doing, we’re all adults here. | https://realpython.com/lessons/python-class-creation/#t=426.48 |
| So, how do you signal danger? Well, Python has public and non-public members. | https://realpython.com/lessons/python-class-creation/#t=431.34 |
| 07:16 | https://realpython.com/lessons/python-class-creation/#t=436.77 |
| Non-public members are indicated by putting an underscore in front of their | https://realpython.com/lessons/python-class-creation/#t=436.77 |
| names. This isn’t enforced in any way. | https://realpython.com/lessons/python-class-creation/#t=441.16 |
| People using the object can touch these attributes and call these methods, | https://realpython.com/lessons/python-class-creation/#t=444.63 |
| but you’re warning them that they’re not really part of the public-facing | https://realpython.com/lessons/python-class-creation/#t=448.47 |
| interface, and they might change. How intensely you use these ideas | https://realpython.com/lessons/python-class-creation/#t=451.41 |
| is kind of a style thing. | https://realpython.com/lessons/python-class-creation/#t=456.43 |
| 07:38 | https://realpython.com/lessons/python-class-creation/#t=458.17 |
| I don’t tend to use non-public values very much unless there’s an important | https://realpython.com/lessons/python-class-creation/#t=458.17 |
| reason why. For example, if I’ve got two values that must be set together, | https://realpython.com/lessons/python-class-creation/#t=461.77 |
| I might store them with underscores and provide a method for changing them. | https://realpython.com/lessons/python-class-creation/#t=466.41 |
| 07:49 | https://realpython.com/lessons/python-class-creation/#t=469.91 |
| At the same time, I have come across code that’s the other way though. | https://realpython.com/lessons/python-class-creation/#t=469.91 |
| One of the libraries I’ve contributed to once in a while is called Asciimatics. | https://realpython.com/lessons/python-class-creation/#t=474.31 |
| It’s a terminal-based animation and TUI builder. | https://realpython.com/lessons/python-class-creation/#t=478.56 |
| 08:01 | https://realpython.com/lessons/python-class-creation/#t=481.39 |
| The core maintainer really likes his non-public attributes. | https://realpython.com/lessons/python-class-creation/#t=481.39 |
| Pretty much everything is non-public, with special mechanisms for exposing the API. | https://realpython.com/lessons/python-class-creation/#t=484.03 |
| I haven’t actually had a chat with him as to why, | https://realpython.com/lessons/python-class-creation/#t=488.89 |
| but I suspect he used to write object-oriented code in another language and has | https://realpython.com/lessons/python-class-creation/#t=492.15 |
| carried the habit over. | https://realpython.com/lessons/python-class-creation/#t=496.17 |
| 08:19 | https://realpython.com/lessons/python-class-creation/#t=499.59 |
| You’ve already seen .__init__(), and I’ve spoken about other special methods | https://realpython.com/lessons/python-class-creation/#t=499.59 |
| denoted by their double underscores. | https://realpython.com/lessons/python-class-creation/#t=503.24 |
| Key functionality provided by Python in classes is mostly built using these | https://realpython.com/lessons/python-class-creation/#t=506.23 |
| kinds of methods. Although they are a system thing, | https://realpython.com/lessons/python-class-creation/#t=511.14 |
| there’s nothing stopping you from using the same mechanism. | https://realpython.com/lessons/python-class-creation/#t=514.24 |
| 08:37 | https://realpython.com/lessons/python-class-creation/#t=517.83 |
| Do note that how they show up is a bit different though. | https://realpython.com/lessons/python-class-creation/#t=517.83 |
| Any member with two leading underscores gets renamed. | https://realpython.com/lessons/python-class-creation/#t=521.46 |
| It kind of hides the member hides—as in, makes it less obvious. | https://realpython.com/lessons/python-class-creation/#t=524.94 |
| 08:50 | https://realpython.com/lessons/python-class-creation/#t=530.26 |
| You can still do whatever you like with it, | https://realpython.com/lessons/python-class-creation/#t=530.26 |
| but you can think of it as an extra-special warning. | https://realpython.com/lessons/python-class-creation/#t=532.54 |
| If the single underscore is a note in the manual saying you probably shouldn’t | https://realpython.com/lessons/python-class-creation/#t=535.3 |
| do that, this is the sticker sealing your device shut, saying voids | https://realpython.com/lessons/python-class-creation/#t=539.16 |
| warranty. The sticker doesn’t stop you, | https://realpython.com/lessons/python-class-creation/#t=543.96 |
| but you really should know what you’re doing. | https://realpython.com/lessons/python-class-creation/#t=546.34 |
| 09:09 | https://realpython.com/lessons/python-class-creation/#t=549.04 |
| These special methods get renamed by Python. | https://realpython.com/lessons/python-class-creation/#t=549.04 |
| This renaming is called name mangling. For example. | https://realpython.com/lessons/python-class-creation/#t=552.06 |
| .__member gets renamed as .__ClassName__member. | https://realpython.com/lessons/python-class-creation/#t=556.13 |
| 09:21 | https://realpython.com/lessons/python-class-creation/#t=561.06 |
| Just like with the single underscore, I can get at it if I know the name, | https://realpython.com/lessons/python-class-creation/#t=561.06 |
| but you can’t really claim ignorance if you’re going hunting for things. | https://realpython.com/lessons/python-class-creation/#t=564.97 |
| This works for both attributes and methods. | https://realpython.com/lessons/python-class-creation/#t=569.46 |
| 09:34 | https://realpython.com/lessons/python-class-creation/#t=574.7 |
| Next up, | https://realpython.com/lessons/python-class-creation/#t=574.7 |
| I’ll dive into the various ways you can associate data with a class, covering | https://realpython.com/lessons/python-class-creation/#t=575.34 |
| more information about attributes. | https://realpython.com/lessons/python-class-creation/#t=579.67 |
| Oct. 31, 2023 | https://realpython.com/lessons/python-class-creation/#comment-ab4cb0da-994a-4b7c-aebc-f100f3e5f9d0 |
| Oct. 31, 2023 | https://realpython.com/lessons/python-class-creation/#comment-eafb3a08-f51f-4b88-af2d-663867098983 |
| Become a Member | https://realpython.com/account/join/ |
| https://realpython.com/videos/why-oop-python/ |
| Overview | https://realpython.com/courses/python-class-object/ |
| https://realpython.com/lessons/python-attributes/ |
|
Class Concepts: Object-Oriented Programming in Python (Overview) 03:22
| https://realpython.com/videos/python-class-object-overview/ |
|
The Case for Object-Oriented Programming 09:55
| https://realpython.com/videos/why-oop-python/ |
|
Class Creation 09:43
| https://realpython.com/lessons/python-class-creation/ |
|
Attributes 06:44
| https://realpython.com/lessons/python-attributes/ |
|
Properties and Descriptors 07:51
| https://realpython.com/lessons/python-properties-and-descriptors/ |
|
Class Methods 08:19
| https://realpython.com/lessons/python-methods/ |
|
A Complete Example: Putting It All Together 10:22
| https://realpython.com/lessons/python-class-object-review/ |
|
Class Concepts: Object-Oriented Programming in Python (Summary) 04:34
| https://realpython.com/lessons/python-class-object-summary/ |
| Privacy Policy | https://realpython.com/privacy-policy/ |
Viewport: width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover