Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically defining a class: type vs types.new_class

Tags:

python

Aside from types.new_class's capability to define the keyword arguments when creating a class. Are there any major differences between the two approaches?

import types

First = type('First',(object,),{'asd':99})
k = First()

Second = types.new_class('Second',(object,),{},lambda x:x)
x = Second()
like image 864
Carlos Miguel Colanta Avatar asked Dec 19 '16 02:12

Carlos Miguel Colanta


People also ask

Why would you use metaclasses?

A metaclass is most commonly used as a class-factory. When you create an object by calling the class, Python creates a new class (when it executes the 'class' statement) by calling the metaclass.

What does metaclass mean in Python?

A metaclass in Python is a class of a class that defines how a class behaves. A class is itself an instance of a metaclass. A class in Python defines how the instance of the class will behave. In order to understand metaclasses well, one needs to have prior experience working with Python classes.

How do you create a class type 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.

What is types SimpleNamespace?

class types. 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.


2 Answers

Are there any major differences between the two approaches?

Yes. The answer involves a concept called "metaclasses".

[Metaclasses] are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why). ⸺ Tim Peters, author of Zen of Python (source)

If you think you're in that 99%, then read no further, feel free to just use type. It's just as good as types.new_class except for in the rare situation that you're using metaclasses.

If you want to know more about metaclasses, I suggest you take a look at some of the high quality answers posted to "What are metaclasses in Python?". (I recommend this one.)

Once you understand what a metaclass is, the answer is fairly self-evident. Since type is a specific metaclass, it will only work if you want to create classes that use it as their metaclass.

However, if you want to use a non-default metaclass

class MySimpleMeta(type):
    pass

and a static class won't do

class MyStaticClass(object, metaclass=MySimpleMeta):
    pass

then you can use types.new_class

import types

MyStaticClass = types.new_class("MyStaticClass", (object,), {"metaclass": MySimpleMeta}, lambda ns: ns)
# this is equivalent to the above class.

(As a brief aside, the reason that it requires a callable (e.g. lambda ns: ns) instead of a dictionary is because metaclasses are allowed to care about the order in which the attributes are defined. )

like image 61
timotree Avatar answered Oct 07 '22 02:10

timotree


I realise this is late, and hence you've already likely answered this yourself.

Firstly, it seems that you misunderstand the kwds argument of types.new_class; it is the class keyword arguments, e.g

class MyMeta(type):
    def __new__(metacls, name, bases, attrs, **config):
        print(config)
        return super().__new__(metacls, name, bases, attrs)

    def __init__(cls, name, bases, attrs, **config):
        super().__init__(name, bases, attrs)

class SomeCls(metaclass=MyMeta, debug=True):
    pass

>> {'debug': True}

is analogous to (without the print)

SomeCls = types.new_class("SomeCls", (), {'debug':True})

These meta-arguments are useful when configuring meta-classes.

I am not really sure as to why new_class was designed to accept a callable vs a dict directly, but I suspect it was to avoid implicit shared state between "new" classes that did not inherit from one another.

like image 1
Angus Hollands Avatar answered Oct 07 '22 01:10

Angus Hollands