yet another modifying locals() question

E

Ed Anuff

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:
.... l['b'] = 1
........ f(locals())
....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.

Is there a reason why this works and is it safe to rely on it or is
there a better approach? BTW, this works in a program too, it's not
just an artifact of the command line interpreter globals() = locals()
thing.

Thanks

Ed
 
S

Steven D'Aprano

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.


... l['b'] = 1
...... f(locals())
...

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.
 
E

Ed Anuff

Metaclasses are left as an exercise for the reader.

The parent class has a metaclass, which is why I was trying this
approach instead, since it let me get at the class attributes before
the metaclass did. Overriding the metaclass looked to be a much more
messy proposition, but I think I've got that working now. Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top