3

I'm having headache trying to understand the cyclic relationship that exit between the metaclass type, the object class, and the class type.

I'm trying to understand how python makes everything an object.is it because everything is an instance of the metaclass type or is it because everything is a subclass of object class.

if its because of being subclass of object class, does that mean if the class object was named class pyobj. Would that mean that everything in Python starts with pyobj?

I know objects created by metaclass are types/classes, this types are then used to create other object.

From this:

>>> isinstance(type, object)
True
>>> isinstance(object,type)
True
>>> issubclass(object,type)
False
>>> issubclass(type,object)
True

Is it safe to say that python creates the class object first using the type metaclass (I'm simplifying the metaclass for brevity).

type('object',(),{})

which implies class object is a class of class type and it does not inherit any attributes other class.

Then it creates the class type:

type('type', (object,),{})

implying type class is class of class type and it inherits attributes from the object class.

Then creates the other classes by inheriting from the class object

type('dict', (object,), {})  
type('Animal', (object), {})

which similar to creating an Animal class as :

class Animal:
     pass

Does this mean the metaclass used to create the class object is still the one used to create this Animal class or is the metaclass type used by default ?

Which type is being used, is it the metaclass type or the type class that was created after object was created ?

Where does the class type created with the base class object come into play ?

I have also tried to understand what really is going on between the object and the class from all he responses above and in this article http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html

I'm still getting confused. What is the relation between this two class in terms of object creation?

Will I ever get this or is it a chicken and egg situation?

1

2 Answers 2

2

Python's core types really do have a chicken and egg situation going on. type inherits from object, but object is an instance of type.

You can't really reason about which of object or type is defined first in Python, because in regular Python code you could not set up their relationship. The Python interpreter gets to do it by fiddling with the internals before the environment is set up, so it doesn't matter if the types are not completely defined up front.

In your example where you call type to create new object and type types, you're not actually getting objects that are equivalent to the real type and object, as your new object type is an instance of the builtin type metaclass, not the hand-made type metaclass you create later.

Here's an illustration of roughly how the interpreter goes about it. The code doesn't actually work, since you can't create a new-style class without inheriting from object, nor can you reassign a type object's __class__ attribute (to make object an instance of type). If you could, you could start up your own independent type system!

my_object = type('my_object', (), {}) # this doesn't work right, it inherits from object
my_type = type('my_type', (my_object,), {})
my_object.__class__ = my_type     # this doesn't work at all (it will raise an exception)
Sign up to request clarification or add additional context in comments.

Comments

0

If type is a chicken and object is an egg then C is the dinosaurs (at least when using the most popular python implementation, Cpython). Cpython speeds up things by using C to produce most common objects. So the circular reference is not an issue, technically the dinosaur laid the chicken egg and birthed the live chicken. If that hurts to think about it, then don't.

Once you're in Python land, considering an object as the root of everything is a good starting place. That's what allows us to pass around classes and functions in the following example:

def my_func():
    pass

class SimpleClass:
    pass

class MetaClass(type):
    pass

class MetaMadeClass(metaclass=MetaClass):
    pass

for o in (str, 'hello', object, object(), type, SimpleClass, MetaClass, MetaMadeClass, print, my_func):
    print(o)
    print('  ', o.__class__)
    try:
         print('  ', o.__mro__)
    except:
         print('   ---   ')  
    try:
         print('  ', o.__call__)
    except:
         print('   ---   ')  
    print('  ', o.__new__)
    print('  ', o.__init__)

Maybe someone can place a table here of the output but I'll summarise the interesting ones.

You'll notice a lot of the results have 'built-in' in their names, that's letting you know your not dealing with pure python objects.

In the example, when an attribute is not found on 'hello' Python checks __class__. It'll then follow str's MRO to return str.__init__ and object.__new__.

Objects that have __class__ = type are called classes. That includes str, object and even type itself! In the example, Simple.__call__ results in invoking type.__call__. It is the methods in type that configure an object to pass for an instance of that class e.g. it sets __class__ to the appropriate value.

I'm not sure if type is technically a metaclass because it's C code making Python classes, but it can be subclassed and then you definitely have a python class that makes python classes. It allows you to do extreme things like set __class__ to something completely different, or not return an instance at all, but extreme approaches require an extremely good reason to do it.

Side note on Cpython

You might guess correctly that the int type is implemented in C for efficiency, but even then low int's are handled differently to high int's. Consider this:

for a, b in [(1, 1), (10**100, 10**100)]:
    print(a is b)

# Output:
#     True
#     False

Cpython goes ahead and generates instances of low integers and reuses them while larger numbers get made on the fly. The result is the 1's are references to the same object while the 10**100's are two separate object. Point is, if I can indulge in another science analogy, everyday Python is like Newtonian physics and you're heading into the realm of quantum mechanics. I'm tired now...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.