Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

object is subclassed during dynamic type creation but not during classic class definition in python2

We know that this creates a class:

class X:
    a = 1

And, in Python 3, due to new style classes, X automatically inherits from object, but in Python 2, it doesn't:

>>> X.__bases__ # Python 2
()
>>> X.__bases__ # Python 3
(<class 'object'>,)

And we also know that we can dynamically create such a class using type factory:

X = type("X",(object,), {"a":1})
      name^   ^bases     ^ "class" body

However, if we omit the object in the bases tuple just as we did with class syntax, we inherit from object in python3 and, unexpectedly, in python2 as well:

X = type("X", ( ), {"a":1})
               ^ empty bases tuple
>>> X.__bases__ # Python 2
(<type 'object'>,)
>>> X.__bases__ # Python 3
(<class 'object'>,)

I expected X.__bases__ to be empty in python 2.
And it's not such a documented feature, I hardly find something about this on internet.

In fact, python's official documentation contradictory states that:

the bases tuple itemizes the base classes and becomes the __bases__ attribute

But, as shown above, () still leads to (<type 'object'>,) in Python 2, so it's not really true that it becomes the __bases__ attribute.

Can anyone explain this behavior?

like image 920
Adelin Avatar asked Jun 05 '19 06:06

Adelin


People also ask

How do you create a dynamic object in Python?

Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. The above syntax returns the type of object.

What does __ class __ mean in Python?

__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .

What object model is used by Python?

Python is an object-oriented (OO) programming language. Unlike some other object-oriented languages, Python doesn't force you to use the object-oriented paradigm exclusively: it also supports procedural programming with modules and functions, so you can select the best paradigm for each part of your program.

How do you create a type object in Python?

First, extract the class body as string. Second, create a class dictionary for the class namespace. Third, execute the class body to fill up the class dictionary. Finally, create a new instance of type using the above type() constructor.


1 Answers

Let's look into this Python 2 shell.

>>> class X1:
...     a = 1
... 
... X2 = type('X2', (), {'a': 1})
>>> type(X1)
0: <type 'classobj'>
>>> type(X2)
1: <type 'type'>
>>> import types
>>> assert types.ClassType is type(X1)

types.ClassType is described as:

The type of user-defined old-style classes.

Basically type in the new-style classes' default metaclass. If you want metaprogramming in the old style, you can use types.ClassType in the same way.

>>> X3 = types.ClassType('X3', (), {'a': 1})
>>> X3.__bases__
2: () 

For the reference, excerpt from Python 2's New-style and classic classes:

Classes and instances come in two flavors: old-style (or classic) and new-style.

Up to Python 2.1 the concept of class was unrelated to the concept of type, and old-style classes were the only flavor available. For an old-style class, the statement x.__class__ provides the class of x, but type(x) is always <type 'instance'>. This reflects the fact that all old-style instances, independent of their class, are implemented with a single built-in type, called instance.

New-style classes were introduced in Python 2.2 to unify the concepts of class and type. A new-style class is simply a user-defined type, no more, no less. If x is an instance of a new-style class, then type(x) is typically the same as x.__class__ (although this is not guaranteed -- a new-style class instance is permitted to override the value returned for x.__class__).

like image 75
saaj Avatar answered Oct 28 '22 04:10

saaj