Skip to content Skip to sidebar Skip to footer

How Does Everything Is An Object Even Work?

I understand the principal theory behind Everything is an Object but I really don't understand how it is implemented under the hood. Functions So: foo(4) is the same as foo.__call_

Solution 1:

I think what you're getting confused with is that although all of Python's variables might be objects and all the properties of those variables might be objects, there is a limit. I mean, for a normal class the structure usually goes:

myclass -> classobj ->type

which you can see if you try this in the console:

>> classA:
..    pass
..

>> printtype(A)
<type'classobj'>
>> printtype(type(A))
<type'type'>

but if you try and go deeper than type, you just get type. type is the base object for all objects in Python.

>> printtype(type(type(A)))
<type 'type'>
>> printtype(type(type(type(type(A)))))
<type 'type'>

Not only do you get the same base class/object type, but you get the same instance of that type for the class instance of A, so although you can do an infinite recursion of the function type (ie. type(type(type(type(... ))))), you won't be going anywhere (ie. not exploring a bottomless pit of infinite memory.)

>> id(type(type(type(A)))
505578544
>> id(type(type(type(type(A))))
505578544

The same principle applies for all the objects in Python and all the properties of the objects in Python since they too are objects, but they are all finite.

Answering one of your earlier questions,

foo.__call__ is the same instance of 'method-wrapper' as foo.__call__.__call__

So nothing is stopping you from doing a very long line with foo.__call__.__call__.__call__...

Python plays a trick on you in that foo.__call__ gives a instance to 'method-wrapper', and inside that 'method-wrapper' class there is a function/variable also called __call__ that points to the same instance of that class.

Solution 2:

Your assumption that if everything is an object, foo(4) must automatically translate to foo.__call__(4) is wrong.

Python can first check if the object foo is a function, and if so call it, and do other things (like look for a __call__ attribute) otherwise.

Solution 3:

You can think of an "object" as a pointer to it's dictionary of data members and a pointer to its type's dictionary of data members (usually including methods of the type). These are usually a finite space and the type's dictionary is shared by all objects of the type. (This is an over-simplification, but probably good enough to understand why it isn't infinite memory).

Solution 4:

The id anomaly is caused by early reference counting: the Python memory manager frees 'a'.upper too early, and then 'b'.upper gets allocated to the same memory address.

Early free:

>>>id('a'.upper), id('b'.upper)
(3073677900L, 3073677900L)

No early free:

>>> x, y = 'a'.upper, 'b'.upper
>>> id(x), id(y)
(3073678252L, 3073677900L)
>>> x, y
(<built-in method upper of strobject at 0xb7317b20>, <built-in method upper of strobject at 0xb7317b40>)

Comparison by reference:

>>> 'a'.upper is'b'.upper
False

Post a Comment for "How Does Everything Is An Object Even Work?"