Pablo Fernandez
Pablo Fernandez

Reputation: 287400

Is there a way to modify a class in a class method in Python?

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")

Upvotes: 0

Views: 690

Answers (3)

Alex Martelli
Alex Martelli

Reputation: 881575

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

Upvotes: 0

balpha
balpha

Reputation: 50898

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.

Upvotes: 5

jkp
jkp

Reputation: 81278

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.

Upvotes: 0

Related Questions