tags:

views:

136

answers:

3

I wanted to do something like setattr to a class in class method in Python, but the class doesn't exist so I basically get:

NameError: global name 'ClassName' is not defined

Is there a way for a class method to modify the class? Something like this but that actually works:

class ClassName(object):
    def HocusPocus(name):
        setattr(ClassName, name, name)

    HocusPocus("blah")
    HocusPocus("bleh")
+5  A: 

Class methods get the class passed as the first argument:

class Bla(object):
    @classmethod
    def cm(cls,value):
        cls.storedValue = value

Bla.cm("Hello")

print Bla.storedValue # prints "Hello"


Edit: I think I understand your problem now. If I get it correctly, all you want to do is this:

class Bla(object):
    storedValue = "Hello again"

print Bla.storedValue # prints "Hello again"

Class creation in Python (pretty much) simply means:

  1. Create a fresh namespace.
  2. Run the code that you find inside the class body using this namespace
  3. Put everything that's left in the namespace into the class as class attributes.

Since storedValue is in the namespace after step 2, it's turned into a class attribute in step 3.

balpha
Is there a way to run cm in the body of Bla?
J. Pablo Fernández
Not with the intended result (Bla doesn't exist yet). But if you just want to set the class attribute storedValue on class creation, what's wrong with just saying storedValue = "Hello" in the body?
balpha
See my edit to the answer.
balpha
That's just a member of the class. I'm trying to simplify the ugly and verbose process of creating properties.
J. Pablo Fernández
Then you really have to explain more. Your code example replaces the most important part by "...", which makes it hard to understand what you're attempting.
balpha
balpha, I don't think it places the most important part in .... I've removed those just in case. The example code still doesn't run. Getting to run something like that would be very helpful. The problem: ClassName doesn't exist when def HocusPocus is evaluated.
J. Pablo Fernández
I understand that problem, and it's not solvable in the way you want to. You cannot writingly access the class namespace from within a function called during class creation. That's why you need to *explicitely* say what *exactly* you're trying to achieve, so we can help you.
balpha
A: 

Another way you could do this would be to use a class decorator, though these are only available from Python 2.6 onwards IIRC.

Something like this:

def addattributes(cls):
    cls.foobar = 10
    return cls

@addattributes
class MyClass(object):
    pass

print MyClass.foobar

This kind of this most useful when you want to "decorate" a number of classes with some specific functionality / properties. In your case, if you only want to do this once, you might just want to use class methods as previously shown.

jkp
A: 

While many good suggestions have been advanced, the closest one can get to the originally requested code, that is:

class ClassName(object):
    def HocusPocus(name):
        setattr(ClassName, name, property(fget=..., fset=...))

    HocusPocus("blah")
    HocusPocus("bleh")

is this:

class ClassName(object):

    def HocusPocus(name):
        return property(fget=..., fset=...)

    blah = HocusPocus("blah")
    bleh = HocusPocus("bleh")

I'm assuming the mysterious ... redacted parts need access to name too (otherwise it's not necessary to pass it as an argument).

The point is that, within the class body, HocusPocus is still just a function (since the class object doesn't exist yet until the class body finishes executing, the body is essentially like a function body that's running in its local dict [without the namespace optimizations typically performed by the Python compiler on locals of a real function, but that only makes the semantics simpler!]) and in particular it can be called within that body, can return a value, that value can be assigned (to a local variable of the class body, which will become a class attribute at the end of the body's execution), etc.

If you don't want ClassName.HocusPocus hanging around later, when you're done executing it within the class body just add a del statement (e.g. as the last statement in the class body):

    del HocusPocus
Alex Martelli
The problem there is that you need to repeat yourself: blah and "blah".
J. Pablo Fernández
The other problem is that I don't see a way to write fget and fset to get and set the attribute name in the object.
J. Pablo Fernández