yet another modifying locals() question

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Mon Sep 14 05:15:14 CEST 2009


On Sun, 13 Sep 2009 18:52:47 -0700, Ed Anuff wrote:

> I know that locals() is not supposed to be modifiable under most
> circumstances, but I'm trying to solve a situation where I'm dynamically
> generating some class attributes and it seemed to be the best way, so I
> tried something out that seems to work but I'm not sure that it's
> kosher:

Given that the docs state not to rely on modifying locals(), I think it 
is safe to say it's NOT kosher. If it works for you, you're lucky, but it 
might stop working in the future.



>>>> def f(l):
> ...    l['b'] = 1
> ...
>>>> class A:
> ...    f(locals())
> ...
>>>> A.b
> 1

> In my code, I'm doing something quite a bit more complex than just
> assigning a single attribute, but this is the simplest use case example.

If you want to dynamically assign attributes after the class is created, 
setattr() is your friend:


class A:
    pass

setattr(A, 'b', 1)  # set a class attribute


With full knowledge of the risks of exec'ing untrusted data, you can use 
exec:

class A:
    exec('b = 1')



For advanced use, you can look at class decorators and metaclasses.

def decorator(cls):
    # Add a class attribute b to the cls.
    cls.b = 1
    return cls


@decorator
class A:
    pass


The above @ syntax requires Python 2.6 or better, but in older versions 
you can write:

class A:
    pass
A = decorator(A)


To make it even more dynamic, write a decorator factory:

def decorator(name):
    def inner(cls):
        setattr(cls, name, 1)
        return cls
    return inner

class A:
    pass
A = decorator('b')(A)



Metaclasses are left as an exercise for the reader.



-- 
Steven



More information about the Python-list mailing list