Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - type(name,bases,dict)

Docs:

With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the __dict__ attribute.

While learning Python I have come across this use of type as "a dynamic form of the class statement", this seems very interesting and useful and I wish to understand it better. Can someone clearly explain the role of __name__, __bases__, and __dict__ in a class and also give example where type(name, bases, dict) comes into its own right.

like image 370
Phoenix Avatar asked Mar 24 '14 12:03

Phoenix


People also ask

What is type () in Python?

The type() function is used to get the type of an object. Python type() function syntax is: type(object) type(name, bases, dict)

What is Obj __ dict __?

object.__dict__ A dictionary or other mapping object used to store an object's (writable) attributes.

What is a dict type?

The type dict is a generic class, signified by type arguments within [...] . For example, dict[int, str] is a dictionary from integers to strings and dict[Any, Any] is a dictionary of dynamically typed (arbitrary) values and keys. list is another generic class.

What is SimpleNamespace Python?

SimpleNamespace. A simple object subclass that provides attribute access to its namespace, as well as a meaningful repr. Unlike object , with SimpleNamespace you can add and remove attributes. If a SimpleNamespace object is initialized with keyword arguments, those are directly added to the underlying namespace.


2 Answers

When you define a class:

class Foo(Base1, Base2):
    bar = 'baz'

    def spam(self):
         return 'ham'

Python essentially does this:

def spam(self):
    return 'ham'
body = {'bar': 'baz', 'spam': spam}

Foo = type('Foo', (Base1, Base2), body)

where Foo is then added to the namespace the class statement was defined in.

The block under the class statement is executed as if it was a function with no arguments and the resulting local namespace (a dictionary) forms the class body; in this case a dictionary with 'bar' and 'spam' keys is formed.

You can achieve the same result by passing a name string, a tuple of base classes and a dictionary with string keys to the type() function.

Once you start exploring metaclasses as well (which are essentially subclasses of type() , letting you customize how classes are created), you'll find that body doesn't have to be a plain dictionary. PEP 3115 - Metaclasses in Python 3 expanded the possible values to anything dict like, letting you implement all sorts of interesting class behaviour by letting you use augmented dictionaries for the class body. The new Python 3.4 enum module for example, uses an OrderedDict() instance instead, to preserve attribute ordering.

like image 78
Martijn Pieters Avatar answered Sep 19 '22 09:09

Martijn Pieters


Just like

a = Foo()

creates an instance of Foo and assigns it to a,

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

creates an instance of type and assigns it to Foo. Not only does this allow you to create classes dynamically (similar to, but not as restricted as, using lambda to create a function), but it lets you (correctly) think of type not as a function, but as a type itself. An instance of type is a class object. type.__new__ creates the object, type.__init__ initializes it, type.__call__ lets you use the class as a callable object (which in turn is how Foo() creates and initializes instances of Foo).

Understanding type is how you understand metaclasses. When you don't specify a metaclass, Python uses type to create the class, as if you had written (in Python 2.x)

class Foo(object):
    __metaclass__ = type

Just like you can subclass ordinary classes, you can subclass type to create your own metaclass!

class mymetaclass(type):
    def __new__(cls, name, bases, dict):
        print "Creating a subclass of {0} named {1}".format(name, bases)
        print "{0} will have the following attributes:".format(name)
        for key in dict:
            print " * {0}".format(key)

# This class statement is (roughly) identical to:
#
# def foo_init(self, x):
#    self.y = x
#
# Foo = mymetaclass('Foo', (object,), { 'a': 3, '__init__': foo_init })
# (The class statement will also ensure that `__module__` and `__metaclass__`
# are in the dict passed to mymetaclass.__new__.)
class Foo(object):
    __metaclass__ = mymetaclass
    a = 3
    def __init__(self, x):
        self.y = x

If you run the above, you'll see output that is generate as the class statement is executed, because mymetaclass.__new__ is executed when the class statement is executed.

like image 22
chepner Avatar answered Sep 20 '22 09:09

chepner