Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add attribute to python class

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)
like image 565
Roberto Avatar asked Nov 09 '22 08:11

Roberto


1 Answers

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.

like image 97
Kevin Avatar answered Nov 27 '22 19:11

Kevin