|
| https://realpython.com/ |
| Start Here | https://realpython.com/start-here/ |
|
Learn Python
| https://realpython.com/lessons/python-class-internals/ |
| 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-internals/ |
| 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-internals%2F |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=python-class-inheritance |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=python-class-inheritance |
| https://realpython.com/courses/python-class-inheritance/#team |
| Inheritance and Internals: Object-Oriented Programming in Python | https://realpython.com/courses/python-class-inheritance/ |
| Christopher Trudeau | https://realpython.com/courses/python-class-inheritance/#team |
| Recommended Tutorial | https://realpython.com/python-classes/ |
| Course Slides (.pdf) | https://realpython.com/courses/python-class-inheritance/downloads/python-class-inheritance-slides/ |
| Sample Code (.zip) | https://realpython.com/courses/python-class-inheritance/downloads/python-class-inheritance-code/ |
| Ask a Question | https://realpython.com/lessons/python-class-internals/#discussion |
| https://realpython.com/feedback/survey/course/python-class-inheritance/liked/?from=lesson-title |
| https://realpython.com/feedback/survey/course/python-class-inheritance/disliked/?from=lesson-title |
| Transcript | https://realpython.com/lessons/python-class-internals/#transcript |
| Discussion (6) | https://realpython.com/lessons/python-class-internals/#discussion |
| 00:00 | https://realpython.com/lessons/python-class-internals/#t=0.57 |
| In the previous lesson, I introduced you to multiple inheritance. | https://realpython.com/lessons/python-class-internals/#t=0.57 |
| In this lesson, | https://realpython.com/lessons/python-class-internals/#t=4.17 |
| I’ll show you different bits about class internals and how you can use them to | https://realpython.com/lessons/python-class-internals/#t=4.9399999999999995 |
| make more powerful code. In part one of this multi-part course, | https://realpython.com/lessons/python-class-internals/#t=8.39 |
| I showed you how the @property and @.setter decorators work to let you write code | https://realpython.com/lessons/python-class-internals/#t=13.35 |
| that makes methods behave like attributes. | https://realpython.com/lessons/python-class-internals/#t=17.03 |
| 00:20 | https://realpython.com/lessons/python-class-internals/#t=20.41 |
| This is part of something called the descriptor protocol. | https://realpython.com/lessons/python-class-internals/#t=20.41 |
| A protocol in Python is a loose collection of functions— | https://realpython.com/lessons/python-class-internals/#t=24.34 |
| or in this case, methods—that act as a promise. | https://realpython.com/lessons/python-class-internals/#t=27.28 |
| 00:30 | https://realpython.com/lessons/python-class-internals/#t=30.84 |
| If you implement their interface, Python will give you some functionality. | https://realpython.com/lessons/python-class-internals/#t=30.84 |
| Many things that seem like magic are actually implemented as protocols | https://realpython.com/lessons/python-class-internals/#t=35.17 |
| underneath, meaning you can write your own classes that behave the same way. | https://realpython.com/lessons/python-class-internals/#t=39.02 |
| 00:43 | https://realpython.com/lessons/python-class-internals/#t=43.24 |
| For example, both iteration and sequence functionality are built on protocols. | https://realpython.com/lessons/python-class-internals/#t=43.24 |
| The descriptor protocol is the one that makes methods act like attributes. | https://realpython.com/lessons/python-class-internals/#t=48.4 |
| 00:53 | https://realpython.com/lessons/python-class-internals/#t=53.29 |
| The @property and @.setter decorators are the simpler version of the descriptor | https://realpython.com/lessons/python-class-internals/#t=53.29 |
| protocol. They abstract away a deeper mechanism that uses dunder methods. | https://realpython.com/lessons/python-class-internals/#t=57.79 |
| 01:02 | https://realpython.com/lessons/python-class-internals/#t=62.97 |
| .__set_name__(), .__get__(), and .set() are all used to implement the same features those | https://realpython.com/lessons/python-class-internals/#t=62.97 |
| decorators do, and you can override these methods and define your own behavior. | https://realpython.com/lessons/python-class-internals/#t=68.15 |
| 01:13 | https://realpython.com/lessons/python-class-internals/#t=73.55 |
| Lets go look at an example. | https://realpython.com/lessons/python-class-internals/#t=73.55 |
| 01:17 | https://realpython.com/lessons/python-class-internals/#t=77.35 |
| If you ever needed an integer that had a more positive outlook on life, | https://realpython.com/lessons/python-class-internals/#t=77.35 |
| well, let’s build one. One that doesn’t allow negative values. | https://realpython.com/lessons/python-class-internals/#t=81.28 |
| They clog up your aura. | https://realpython.com/lessons/python-class-internals/#t=85.2 |
| 01:27 | https://realpython.com/lessons/python-class-internals/#t=87.63 |
| You can write a class that abstracts a positive integer using the descriptor | https://realpython.com/lessons/python-class-internals/#t=87.63 |
| protocol. First off, | https://realpython.com/lessons/python-class-internals/#t=91.61 |
| .__set_name__() is called when a descriptor is instantiated, and it’s passed | https://realpython.com/lessons/python-class-internals/#t=93.23 |
| the name of the variable it is being assigned to. For example, | https://realpython.com/lessons/python-class-internals/#t=98.19 |
| if you read a line of code that says radius = PositiveInteger, | https://realpython.com/lessons/python-class-internals/#t=101.91 |
| instantiating a PositiveInteger object and storing it in a reference called | https://realpython.com/lessons/python-class-internals/#t=105.88 |
| radius, the name radius gets passed into .__set_name__(). | https://realpython.com/lessons/python-class-internals/#t=109.75 |
| 01:54 | https://realpython.com/lessons/python-class-internals/#t=114.62 |
| What you typically do with that value is store it for later use. | https://realpython.com/lessons/python-class-internals/#t=114.62 |
| I’m sticking it in ._name, logically enough. | https://realpython.com/lessons/python-class-internals/#t=118.73 |
| 02:03 | https://realpython.com/lessons/python-class-internals/#t=123.21 |
| The core of what you do with the descriptor protocol is get and set values. | https://realpython.com/lessons/python-class-internals/#t=123.21 |
| .__get__() is the get part. | https://realpython.com/lessons/python-class-internals/#t=127.77 |
| This method is past the object that the descriptor is attached to and the class | https://realpython.com/lessons/python-class-internals/#t=130.22 |
| of the descriptor itself. | https://realpython.com/lessons/python-class-internals/#t=134.41 |
| 02:16 | https://realpython.com/lessons/python-class-internals/#t=136.53 |
| That’d be the radius and the Circle class in the example I just mentioned. | https://realpython.com/lessons/python-class-internals/#t=136.53 |
| I’m not really sure why they bother passing in the class as you can always get | https://realpython.com/lessons/python-class-internals/#t=142.09 |
| it through self.__class__, but it’s part of the protocol, | https://realpython.com/lessons/python-class-internals/#t=146.39 |
| so it has to be in the signature. | https://realpython.com/lessons/python-class-internals/#t=149.89 |
| 02:32 | https://realpython.com/lessons/python-class-internals/#t=152.9 |
| All the getter for PositiveInteger needs to do is return the associated value. | https://realpython.com/lessons/python-class-internals/#t=152.9 |
| The value is on the instance object under the name associated with this | https://realpython.com/lessons/python-class-internals/#t=158.06 |
| descriptor. | https://realpython.com/lessons/python-class-internals/#t=162.32 |
| 02:43 | https://realpython.com/lessons/python-class-internals/#t=163.62 |
| .__dict__ is the dictionary associated with all Python objects where | https://realpython.com/lessons/python-class-internals/#t=163.62 |
| Python stores the objects attributes. | https://realpython.com/lessons/python-class-internals/#t=168.22 |
| It feels like there’s a lot going on in this line, | https://realpython.com/lessons/python-class-internals/#t=171.7 |
| but all it’s doing is getting the value from the associated instance object. | https://realpython.com/lessons/python-class-internals/#t=174.22 |
| 02:59 | https://realpython.com/lessons/python-class-internals/#t=179.47 |
| There are situations where this won’t work, | https://realpython.com/lessons/python-class-internals/#t=179.47 |
| but I’ll come back to that edge case in a later lesson. All right, | https://realpython.com/lessons/python-class-internals/#t=181.68 |
| you’ve got the getter. Now the setter. | https://realpython.com/lessons/python-class-internals/#t=185.88 |
| This signature takes the instance object associated with the value and the new | https://realpython.com/lessons/python-class-internals/#t=188.87 |
| value to set it to. The purpose of PositiveInteger is to make | https://realpython.com/lessons/python-class-internals/#t=192.76 |
| sure that it can only store positive integer. This line enforces that. | https://realpython.com/lessons/python-class-internals/#t=197.67 |
| 03:23 | https://realpython.com/lessons/python-class-internals/#t=203.9 |
| Once the error checking’s out of the way, | https://realpython.com/lessons/python-class-internals/#t=203.9 |
| now I need to actually assign the value. | https://realpython.com/lessons/python-class-internals/#t=205.89 |
| This uses the same .__dict__ mechanism as the getter, | https://realpython.com/lessons/python-class-internals/#t=208.5 |
| but this time assigning the value to that dictionary. | https://realpython.com/lessons/python-class-internals/#t=211.73 |
| 03:36 | https://realpython.com/lessons/python-class-internals/#t=216.12 |
| Let me scroll down, and you’ll see how this gets used. | https://realpython.com/lessons/python-class-internals/#t=216.12 |
| 03:40 | https://realpython.com/lessons/python-class-internals/#t=220.52 |
| Circles are, so yesterday. Let’s define an Ellipse. | https://realpython.com/lessons/python-class-internals/#t=220.52 |
| The ellipse has two radius-like things: a width and a height. Mathematically, | https://realpython.com/lessons/python-class-internals/#t=224.47 |
| there are a half dozen ways to specify an ellipse, | https://realpython.com/lessons/python-class-internals/#t=229.14 |
| but width and height are commonly used in drawing libraries, | https://realpython.com/lessons/python-class-internals/#t=231.69 |
| so let’s stick with that. Instead of specifying focal points, | https://realpython.com/lessons/python-class-internals/#t=234.27 |
| I want both my width and my height to be positive integers, | https://realpython.com/lessons/python-class-internals/#t=238.6 |
| so I use our newly minted class. | https://realpython.com/lessons/python-class-internals/#t=241.98 |
| 04:05 | https://realpython.com/lessons/python-class-internals/#t=245.39 |
| This is a little tricky, .width and .height here are class attributes, | https://realpython.com/lessons/python-class-internals/#t=245.39 |
| which means the instantiation of PositiveInteger is associated with the | https://realpython.com/lessons/python-class-internals/#t=250.77 |
| Ellipse’s class, not the objects. | https://realpython.com/lessons/python-class-internals/#t=255.28 |
| 04:18 | https://realpython.com/lessons/python-class-internals/#t=258.95 |
| This is how you register a descriptor. Inside Ellipse’s .__init__(), | https://realpython.com/lessons/python-class-internals/#t=258.95 |
| When I go to assign a value, the descriptor on the class is getting invoked, | https://realpython.com/lessons/python-class-internals/#t=264.02 |
| but because the descriptor’s code actually stores the contents on the object, | https://realpython.com/lessons/python-class-internals/#t=268.77 |
| the end result is a value associated with the object, not the class. | https://realpython.com/lessons/python-class-internals/#t=272.61 |
| 04:37 | https://realpython.com/lessons/python-class-internals/#t=277.81 |
| My brain hurts a little when I think about this. | https://realpython.com/lessons/python-class-internals/#t=277.81 |
| You don’t really need to understand this. When you use descriptors, | https://realpython.com/lessons/python-class-internals/#t=280.97 |
| you can treat it like magic. | https://realpython.com/lessons/python-class-internals/#t=283.65 |
| If you build a descriptor and assign it in the class, | https://realpython.com/lessons/python-class-internals/#t=285.33 |
| the end result is stored values with the same name on the object. | https://realpython.com/lessons/python-class-internals/#t=287.45 |
| 04:50 | https://realpython.com/lessons/python-class-internals/#t=290.85 |
| It isn’t magic though. There’s no extra special stuff going on here. | https://realpython.com/lessons/python-class-internals/#t=290.85 |
| From the interpreter’s point of view, | https://realpython.com/lessons/python-class-internals/#t=294.27 |
| it’s a class attribute that references a particular kind of instance object, | https://realpython.com/lessons/python-class-internals/#t=296.38 |
| which implements the descriptor, | https://realpython.com/lessons/python-class-internals/#t=301.16 |
| which when assigned to passes the value through the descriptor protocol to | https://realpython.com/lessons/python-class-internals/#t=303.24 |
| the owning instance object. Does it spoil the magic to know how the trick works? | https://realpython.com/lessons/python-class-internals/#t=308.09 |
| 05:13 | https://realpython.com/lessons/python-class-internals/#t=313.9 |
| Alright, magic or not, let’s see it in practice. Importing … | https://realpython.com/lessons/python-class-internals/#t=313.9 |
| 05:21 | https://realpython.com/lessons/python-class-internals/#t=321.03 |
| and I’ll create an ellipse. | https://realpython.com/lessons/python-class-internals/#t=321.03 |
| 05:25 | https://realpython.com/lessons/python-class-internals/#t=325.83 |
| I’m gonna scroll the top window back up so that you can see the descriptor | https://realpython.com/lessons/python-class-internals/#t=325.83 |
| class. Since I put print statements in the descriptor, | https://realpython.com/lessons/python-class-internals/#t=329.01 |
| you can sort of see what’s going on. | https://realpython.com/lessons/python-class-internals/#t=332.44 |
| 05:35 | https://realpython.com/lessons/python-class-internals/#t=335.12 |
| The .__init__() for Ellipse assigns .width and .height. | https://realpython.com/lessons/python-class-internals/#t=335.12 |
| That assignment triggers .__set_name__() for PositiveInteger because it’s | https://realpython.com/lessons/python-class-internals/#t=338.81 |
| registered as a descriptor, as a class attribute. This gets called twice, | https://realpython.com/lessons/python-class-internals/#t=343.54 |
| once for .width and once for .height. Now, when I access the .width attribute, | https://realpython.com/lessons/python-class-internals/#t=348.37 |
| 05:55 | https://realpython.com/lessons/python-class-internals/#t=355.5 |
| the print() in the getter is issued and returns the value. | https://realpython.com/lessons/python-class-internals/#t=355.5 |
| 06:01 | https://realpython.com/lessons/python-class-internals/#t=361.94 |
| Same goes for .height, and if I try to assign .height, | https://realpython.com/lessons/python-class-internals/#t=361.94 |
| 06:08 | https://realpython.com/lessons/python-class-internals/#t=368.9 |
| I get the error checking in the setter enforcing our positive outlook. | https://realpython.com/lessons/python-class-internals/#t=368.9 |
| No negativity for you. | https://realpython.com/lessons/python-class-internals/#t=373.52 |
| 06:18 | https://realpython.com/lessons/python-class-internals/#t=378.56 |
| Dictionaries aren’t free. They take up more memory than just their contents. | https://realpython.com/lessons/python-class-internals/#t=378.56 |
| The attributes on an object are stored as a dictionary. By default, | https://realpython.com/lessons/python-class-internals/#t=383.58 |
| That dictionary is named .__dict__. | https://realpython.com/lessons/python-class-internals/#t=387.87 |
| 06:31 | https://realpython.com/lessons/python-class-internals/#t=391.07 |
| If you don’t want the overhead cost of a dictionary associated with your class, | https://realpython.com/lessons/python-class-internals/#t=391.07 |
| you can slim it down using the special attribute .__slots__. | https://realpython.com/lessons/python-class-internals/#t=395.31 |
| 06:40 | https://realpython.com/lessons/python-class-internals/#t=400.07 |
| What you put in .__slots__ is a tuple with the names of the attributes your | https://realpython.com/lessons/python-class-internals/#t=400.07 |
| class uses. Technically, it can be a list instead of a tuple, | https://realpython.com/lessons/python-class-internals/#t=404.4 |
| but that has extra overhead as well, | https://realpython.com/lessons/python-class-internals/#t=408.38 |
| and you’re never going to edit the contents. When .__slots__ is present, | https://realpython.com/lessons/python-class-internals/#t=410.18 |
| the underlying .__dict__ gets removed. | https://realpython.com/lessons/python-class-internals/#t=415.34 |
| 06:58 | https://realpython.com/lessons/python-class-internals/#t=418.46 |
| If you attempt to use .__dict__, | https://realpython.com/lessons/python-class-internals/#t=418.46 |
| you’ll get an AttributeError because it isn’t there, and of course, | https://realpython.com/lessons/python-class-internals/#t=420.38 |
| without .__dict__, there is nowhere to put new attributes. | https://realpython.com/lessons/python-class-internals/#t=424.62 |
| 07:08 | https://realpython.com/lessons/python-class-internals/#t=428.48 |
| Attempting to add an attribute that isn’t in .__slots__ will also result in | https://realpython.com/lessons/python-class-internals/#t=428.48 |
| an error. | https://realpython.com/lessons/python-class-internals/#t=433.35 |
| 07:16 | https://realpython.com/lessons/python-class-internals/#t=436.16 |
| Consider this class containing an "x" and a "y" coordinate. By putting "x" and | https://realpython.com/lessons/python-class-internals/#t=436.16 |
| "y" in .__slots__, I get rid of the underlying .__dict__. | https://realpython.com/lessons/python-class-internals/#t=441.2 |
| 07:25 | https://realpython.com/lessons/python-class-internals/#t=445.83 |
| This saves a bit of memory, a little over 400 bytes per object. | https://realpython.com/lessons/python-class-internals/#t=445.83 |
| Remember earlier when I said I’ll save that for later in the lesson? Well, | https://realpython.com/lessons/python-class-internals/#t=450.89 |
| it’s later in the lesson. | https://realpython.com/lessons/python-class-internals/#t=454.44 |
| 07:36 | https://realpython.com/lessons/python-class-internals/#t=456.19 |
| The PositiveInteger descriptor class worked by assuming the instance object it | https://realpython.com/lessons/python-class-internals/#t=456.19 |
| was associated with had a .__dict__. If you use .__slots__, | https://realpython.com/lessons/python-class-internals/#t=460.97 |
| that assumption isn’t valid. | https://realpython.com/lessons/python-class-internals/#t=465.8 |
| 07:48 | https://realpython.com/lessons/python-class-internals/#t=468.41 |
| I played around with this for a while trying to figure out if I could get the | https://realpython.com/lessons/python-class-internals/#t=468.41 |
| two things to work together. | https://realpython.com/lessons/python-class-internals/#t=471.57 |
| I found some code on the internet that showed a way to make it work, | https://realpython.com/lessons/python-class-internals/#t=473.13 |
| but it had two problems. | https://realpython.com/lessons/python-class-internals/#t=475.67 |
| 07:57 | https://realpython.com/lessons/python-class-internals/#t=477.28 |
| Problem one is it resulted in a new .__dict__ being created, | https://realpython.com/lessons/python-class-internals/#t=477.28 |
| which defeats the purpose of .__slots__, | https://realpython.com/lessons/python-class-internals/#t=481.02 |
| and problem two was I couldn’t get it to work in Python 3. | https://realpython.com/lessons/python-class-internals/#t=483.27 |
| 08:06 | https://realpython.com/lessons/python-class-internals/#t=486.71 |
| Python 3 seems to be a bit more aggressive about the constraint. In theory, | https://realpython.com/lessons/python-class-internals/#t=486.71 |
| you could write a descriptor class that stored values in the descriptor class | https://realpython.com/lessons/python-class-internals/#t=491.79 |
| instead of on the instance object. As there can be multiple instance objects, | https://realpython.com/lessons/python-class-internals/#t=495.32 |
| you’d need to store that value in a nested dictionary with the top level keyed on | https://realpython.com/lessons/python-class-internals/#t=500.39 |
| the instance and the second level storing the values for that instance. | https://realpython.com/lessons/python-class-internals/#t=504.85 |
| 08:29 | https://realpython.com/lessons/python-class-internals/#t=509.01 |
| I haven’t tried this, | https://realpython.com/lessons/python-class-internals/#t=509.01 |
| but there’s no reason it wouldn’t work that I can think of. | https://realpython.com/lessons/python-class-internals/#t=510.43 |
| But if you get what I’m laying down, the short version of it is, I just said, | https://realpython.com/lessons/python-class-internals/#t=513.03 |
| reimplement .__dict__, but somewhere else. | https://realpython.com/lessons/python-class-internals/#t=518.13 |
| 08:40 | https://realpython.com/lessons/python-class-internals/#t=520.55 |
| You’ll essentially be losing almost all the gains of .__slots__. Not quite all, | https://realpython.com/lessons/python-class-internals/#t=520.55 |
| but close enough. The short version is don’t mix descriptors and slots. | https://realpython.com/lessons/python-class-internals/#t=524.65 |
| 08:49 | https://realpython.com/lessons/python-class-internals/#t=529.52 |
| It’s a recipe for disaster. | https://realpython.com/lessons/python-class-internals/#t=529.52 |
| 08:53 | https://realpython.com/lessons/python-class-internals/#t=533.19 |
| I hope you’re not tired of dunder stuff. More to come in the next lesson. | https://realpython.com/lessons/python-class-internals/#t=533.19 |
| Dec. 9, 2023 | https://realpython.com/lessons/python-class-internals/#comment-519ad83d-a7ff-456c-85f0-cb8a5ffa77a1 |
| Dec. 9, 2023 | https://realpython.com/lessons/python-class-internals/#comment-456b1116-191a-41ee-847e-7a0a612050b9 |
| Dec. 9, 2023 | https://realpython.com/lessons/python-class-internals/#comment-2487849f-472b-40b0-afff-d46bd8337c9d |
| Dec. 11, 2023 | https://realpython.com/lessons/python-class-internals/#comment-44e695c8-bf7d-43aa-a52f-bfe37a4705a4 |
| Dec. 11, 2023 | https://realpython.com/lessons/python-class-internals/#comment-8a5bcf78-b7a8-40a7-af14-ccfb89ec7d26 |
| Dec. 11, 2023 | https://realpython.com/lessons/python-class-internals/#comment-4cb9a15f-08ca-4ab7-a001-9500a6781d93 |
| Become a Member | https://realpython.com/account/join/ |
| https://realpython.com/lessons/python-multiple-inheritance/ |
| Overview | https://realpython.com/courses/python-class-inheritance/ |
| https://realpython.com/lessons/python-class-special-methods/ |
|
Inheritance and Internals: OOP in Python (Overview) 03:38
| https://realpython.com/videos/python-class-inheritance-overview/ |
|
Inheritance Inside Python 09:07
| https://realpython.com/videos/inheritance-in-python/ |
|
Multiple Inheritance - Multiple Parents 09:30
| https://realpython.com/lessons/python-multiple-inheritance/ |
|
Class Internals 08:58
| https://realpython.com/lessons/python-class-internals/ |
|
More Special Methods 06:50
| https://realpython.com/lessons/python-class-special-methods/ |
|
Classes in the Standard Library 07:23
| https://realpython.com/lessons/python-class-standard-library/ |
|
Abstracts and Interfaces 08:41
| https://realpython.com/lessons/python-class-abstracts-and-interfaces/ |
|
Inheritance and Internals: OOP in Python (Summary) 02:21
| https://realpython.com/lessons/python-class-inheritance-summary/ |
| Privacy Policy | https://realpython.com/privacy-policy/ |
Viewport: width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover