5

Consider the following code:

class Foo():

    pass


Foo.entries = dict()


a = Foo()
a.entries['1'] = 1

b = Foo()
b.entries['3'] = 3

print(a.entries)

This will print:

{'1': 1, '3': 3}

because the entries is added as static attribute. Is there a way monkey patch the class definition in order to add new attributes (without using inheritance).

I managed to find the following way but it looks convoluted to me:

def patch_me(target, field, value):
    def func(self):
        if not hasattr(self, '__' + field):
            setattr(self, '__' + field, value())
        return getattr(self, '__' + field)
    setattr(target, field, property(func))

patch_me(Foo, 'entries', dict)
2
  • You're adding a class attribute, which is shared amongst all instances. If you add it to instances, should instances already created gain the new attribute? Commented Jul 23, 2015 at 14:19
  • Why can't you do a.entries = {'1': 1} instead? Commented Jul 23, 2015 at 14:20

1 Answer 1

1

Ordinarily, attributes are added either by the __init__() function or after instantiating:

foo = Foo()
foo.bar = 'something'  # note case

If you want to do this automatically, inheritance is by far the simplest way to do so:

class Baz(Foo):
    def __init__(self):
        super().__init__()  # super() needs arguments in 2.x
        self.bar = 'something'

Note that classes don't need to appear at the top level of a Python module. You can declare a class inside a function:

def make_baz(value):
    class Baz(Foo):
        def __init__(self):
            super().__init__()  # super() needs arguments in 2.x
            self.bar = value()
    return Baz()

This example will create a new class every time make_baz() is called. That may or may not be what you want. It would probably be simpler to just do this:

def make_foo(value):
    result = Foo()
    result.bar = value()
    return result

If you're really set on monkey-patching the original class, the example code you provided is more or less the simplest way of doing it. You might consider using decorator syntax for property(), but that's a minor change. I should also note that it will not invoke double-underscore name mangling, which is probably a good thing because it means you cannot conflict with any names used by the class itself.

Sign up to request clarification or add additional context in comments.

1 Comment

Functions within a class can add an attribute as much as the init function. In fact, you can have functions to destroy or add properties. For example drawing a square class can have a border method. Only upon calling the border method, the class will get a border property. I prefer to add a border = 0 property in the init function for stuff like that as well, but both ways work. Maybe for a child class BorderlessSquare. Call the parent init function and remove the border property and add some others.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.