How safe is modifying locals()?

Bengt Richter bokr at oz.net
Sat Jul 26 15:11:53 EDT 2003


On Sat, 26 Jul 2003 14:49:41 +0200, Stefan Schwarzer <sschwarzer at sschwarzer.net> wrote:

>Hi Paul
>
>Paul Paterson wrote:
>> This is a very interesting (and Pythonic) approach, thanks for 
>> suggesting it! This is certainly what I would try to do if I were 
>> writing the code from scratch. It may be possible to construct a 
>> "namespace" type object which gets passed to the function.
>
>I think the most common way to make a namespace in Python is
>
>class my_namespace: pass
>...
>my_namespace.a = 'foo'
>my_namespace.b = 'bar'
>
>Such namespaces are very similar to dictionaries:
>
>my_namespace = {}
>...
>my_namespace['a'] = 'foo'
>my_namespace['b'] = 'bar'
>
>but the first approach is a bit more readable.
>
>If you need many containers, you could use:
>
>class Container:
>     pass
>
>c1 = Container()
>c2 = Container()
>...
>c1.foo = 'foo'
>c2.foo = 'bar'
>
>Of course, if you have a better name for your container, that's even
>better. Think of Ian's Point example. :-)
>
Nice summary. Just to round it out, we could add using the type builtin.
I.e., type(cname, bases, cdict) works to create an instant class (new type),
and this can be used for some interesting alternative spellings, e.g.,

A one-off name space object:

 >>> nso = type('',(),{})()
 >>> nso
 <__main__. object at 0x007AC1E0>

BTW, funny that you can have a '' class name this way ;-) (I wonder if it can trigger a bug?)
 >>> `nso.__class__.__name__`
 "''"

 >>> nso.x = 123
 >>> vars(nso)
 {'x': 123}

Anyway, if you want to initialize some default name bindings in the form of class variables,
you can do that simply, even in the one-off one-liner, e.g.,

 >>> nso = type('',(),{'x':123, 'y':'wye'})()
 >>> nso.x, nso.y
 (123, 'wye')

Note that they are class attributes ("variables"), not instance attributes, though:

 >>> nso.x = 'instance attribute' # shadows class attr
 >>> nso.x
 'instance attribute'
 >>> del nso.x # but can be unshadowed
 >>> nso.x
 123

If you want to generate a cdict for class attributes by calling some function, you could, e.g.,

 >>> nso = type('',(),(lambda **kw:kw)(
 ...     x = 456,
 ...     y = 'wye',
 ...     etc = 'and so forth'
 ... ))()

Of course, that's a pretty silly substitute (other than the '' vs 'nso' class name) for

 >>> class nso(object):
 ...     x = 456
 ...     y = 'wye'
 ...     etc = 'and so forth'
 ...
 >>> nso = nso()

but it does show a function (lambda **kw:kw) being called to generate the cdict.
Checking results:

 >>> nso.x
 456
 >>> nso.x, nso.y, nso.etc
 (456, 'wye', 'and so forth')
 >>> vars(nso.__class__).keys()
 ['__dict__', '__module__', 'etc', 'y', 'x', '__weakref__', '__doc__']

BTW, I find it useful to use vars(foo).keys() rather than dir(foo) to avoid inherited stuff.

Of course, if you bind the class to a name instead of instantly ()'ing it, note

 >>> ClassAlias = type('ClassName',(),{})
 >>> ClassAlias
 <class '__main__.ClassName'>

doesn't match very well, and

 >>> ClassName = type('ClassName',(),{})
 >>> ClassName
 <class '__main__.ClassName'>

is a silly substitute for

 >>> class ClassName(object): pass
 ...
 >>> ClassName
 <class '__main__.ClassName'>

Even if you don't bind the name locally, it is bound to the instance
as inst.__class__.__name__, so it may be a good idea to call type with
a reasonable name as the first param, not ''.

Hm, got to rambling again ;-/

Regards,
Bengt Richter




More information about the Python-list mailing list