Reputation: 807
A friend recently asked "How does the CPython Interpreter actually handle OOP (Object Orientated Programming)?".
This question ended up making me confused, as I understand C isn't an Object Orientated language.
I tried Googling it, searching StackOverflow and even reading the CPython Wiki. But I couldn't find anything useful.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def getInfo(self):
return "Name: " + self.name + "\nAge: " + str(self.age)
# How the heck does CPython handle this?
personOne = Person("Bob", 34)
personTwo = Person("Rob", 26)
print( personOne.getInfo() )
print( personTwo.getInfo() )
So now I really wanna know! Just how does the CPython Interpreter handle things like Objects if itself isn't Object Orientated?
Upvotes: 3
Views: 291
Reputation: 281013
The full complexity of Python's OOP implementation is far beyond the scope of a Stack Overflow answer, but it's possible to provide an overview. This will gloss over a lot of details, like metaclasses, multiple inheritance, descriptors, and the C-level API. Still, it should give you a sense of why implementing such a thing is possible, as well as a general impression of how it's done. If you want the full details, you should browse the CPython source code.
An object like an instance of your Person
class consists of the following things:
__weakref__
.A class is also pretty simple. It has
When you define a class with a class
statement, Python bundles up a pointer to the base class you picked (or object
if you didn't pick one) and a dict holding the methods you defined, and that's your new class object. It's kind of like the following tuple
Person = (object,
{'__init__': <that __init__ method you wrote>,
'getInfo': <that getInfo method you wrote>},
those irrelevant bits we're glossing over)
but not a tuple. (At C level, this record is almost, but not quite, implemented as a struct.)
When you create an instance of your class, Python bundles together a pointer to your class and a new dict for the instance's attributes, and that's your instance. It's kind of like the following tuple:
personOne = (Person, {}, those irrelevant bits we're glossing over)
but again, not a tuple. Again, it's almost, but not quite, implemented as a struct at C level.
Then it runs __init__
, passing __init__
the new instance and whatever other arguments you provided to your class:
Person.__init__(personOne, "Bob", 34)
Attribute assignment is translated to setting entries in the object's dict, so the assignments in __init__
:
def __init__(self, name, age):
self.name = name
self.age = age
cause the dict to end up in the following state:
{'name': 'Bob', 'age': 34}
When you call personOne.getInfo()
, Python looks in personOne
's dict, then its class's dict, then its superclass's dict, etc., until it finds an entry for the 'getInfo'
key. The associated value will be the getInfo
method. If the method was found in a class dict, Python will insert personOne
as the first argument. (The details of how it knows to insert that argument are in the descriptor protocol.)
Upvotes: 6
Reputation: 14928
Here's a small thought-experiment: Your CPU is not "object oriented" at all. Instead, it's only able to execute instructions like "add register 1 to register 2 and put the result in register 3" and "if register 5 is greater than zero, then execute this goto statement." And yet somehow the CPU can run Python and other object-oriented languages. How?
Upvotes: 6