git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

about types.new_class and module


MRAB wrote:

> On 2019-03-04 18:02, Jimmy Girardet wrote:
>> Hello,
>> 
>> I'm looking for an explanation where live classes created by
>> types.new_class() :
>> 
>> py> import types
>> 
>> py> types.new_class('A')
>> 
>> types.A
>> 
>> py> types.A
>> 
>> AttributeError: module 'types' has no attribute 'A'
>> 
>> py> _.__module__
>> 
>> 'types'
>> 
>> 
>> The new class comes from `types` module without being inside.
>> 
>> That's annoying to me for my use case :
>> 
>> I'm trying to create dataclasses on the fly using  make_dataclass (which
>> uses types.new_class). For new created classes, I have a cache to not
>> recreate twice the same class.
>> 
>> But I want to be sure not to override an existing class somewhere in the
>> namespace which is already 'types.MyNewclass'. but how to check it if
>> it's not in types ?
>> 
>> To be clear :
>> 
>> make_dataclass('Bla', {}) should raise an error if something named
>> 'types.Bla' already exists.
>> 
>> I hope I'm clear enough.
>> 
> 'new_class' creates a new class with the given name and returns a
> reference to it.
> 
> The class doesn't 'live' anywhere.
> 
> Although you might /think/ that an object lives in a certain namespace,
> it's just that there's a name there that's bound to the object.
> 
> You can, in fact, create 2 classes with the same name.
> 
>  >>> import types
>  >>> t1 = types.new_class('A')
>  >>> t2 = types.new_class('A')
>  >>> t1 is t2
> False

However, the underlying type() call assumes that you are going to inject the 
class into the current module -- which is why the OP's class appears to be 
part of the types module

>>> types.new_class("Foo")
<class 'types.Foo'>

and

>>> type("Foo", (), {})
<class '__main__.Foo'>

appears to be in __main__. This is correct in the majority of cases where 
the class is defined with

class A:
   pass

which can be thought of as syntactic sugar for

A = type("A", (), {})

In the case of types.new_class() it is rather confusing -- perhaps the 
function should follow the example of collections.namedtuple and set the 
__module__ attribute to the caller's namespace.