How to Add Property to a Class Dynamically

How to add property to a class dynamically?

I suppose I should expand this answer, now that I'm older and wiser and know what's going on. Better late than never.

You can add a property to a class dynamically. But that's the catch: you have to add it to the class.

>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

A property is actually a simple implementation of a thing called a descriptor. It's an object that provides custom handling for a given attribute, on a given class. Kinda like a way to factor a huge if tree out of __getattribute__.

When I ask for foo.b in the example above, Python sees that the b defined on the class implements the descriptor protocol—which just means it's an object with a __get__, __set__, or __delete__ method. The descriptor claims responsibility for handling that attribute, so Python calls Foo.b.__get__(foo, Foo), and the return value is passed back to you as the value of the attribute. In the case of property, each of these methods just calls the fget, fset, or fdel you passed to the property constructor.

Descriptors are really Python's way of exposing the plumbing of its entire OO implementation. In fact, there's another type of descriptor even more common than property.

>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

The humble method is just another kind of descriptor. Its __get__ tacks on the calling instance as the first argument; in effect, it does this:

def __get__(self, instance, owner):
return functools.partial(self.function, instance)

Anyway, I suspect this is why descriptors only work on classes: they're a formalization of the stuff that powers classes in the first place. They're even the exception to the rule: you can obviously assign descriptors to a class, and classes are themselves instances of type! In fact, trying to read Foo.bar still calls property.__get__; it's just idiomatic for descriptors to return themselves when accessed as class attributes.

I think it's pretty cool that virtually all of Python's OO system can be expressed in Python. :)

Oh, and I wrote a wordy blog post about descriptors a while back if you're interested.

Dynamically adding @property in python

The property descriptor objects needs to live in the class, not in the instance, to have the effect you desire. If you don't want to alter the existing class in order to avoid altering the behavior of other instances, you'll need to make a "per-instance class", e.g.:

def addprop(inst, name, method):
cls = type(inst)
if not hasattr(cls, '__perinstance'):
cls = type(cls.__name__, (cls,), {})
cls.__perinstance = True
inst.__class__ = cls
setattr(cls, name, property(method))

I'm marking these special "per-instance" classes with an attribute to avoid needlessly making multiple ones if you're doing several addprop calls on the same instance.

Note that, like for other uses of property, you need the class in play to be new-style (typically obtained by inheriting directly or indirectly from object), not the ancient legacy style (dropped in Python 3) that's assigned by default to a class without bases.

How Can I add properties to a class on runtime in C#?

You cannot extend an existing class with new members at runtime. However, you can create a new class using System.Reflection.Emit that has the existing class as base class.

typeBuilder.SetParent(typeof(MyClass));
typeBuilder.DefineProperty("Prop1", ..., typeof(System.Int32), null);
...

See TypeBuilder.DefineProperty Method (String, PropertyAttributes, Type, Type[]) for a full example.

Dynamically adding a property to a class

I don't know why you use operator.methodcaller here.
When you call f.spam=2, it will invoke setter.
setter = operator.methodcaller('set_value', name) means setter(r) = r.set_value(name). Make no sense in your case.

I suggest you write this way, using @classmethod:

class Foo(object):

@classmethod
def get_value(self, name):
# read and return value from database
return -1
@classmethod
def set_value(self, name, value):
# store value in database
pass

def add_metadata_property(name):
setattr(Foo, name, property(Foo.get_value, Foo.set_value))

add_metadata_property('spam')
f = Foo()
f.spam # works!
f.spam = 2

If this helped you, please confirm it as the answer. Thanks!

Declare dynamically added class properties in TypeScript

The problem is that you're adding the new properties at runtime and the compiler has no way of knowing that.

If you know the property names in advance then you can do this:

type Json = {
foo: string;
bar: string;
}

...

const myInstance = new MyClass(someJson) as MyClass & Json;
console.log(myInstance.foo) // no error

Edit

If you do not know the properties in advance then you can't do this:

console.log(myInstance.foo);

Because then you know that foo is part of the received json, you'll probably have something like:

let key = getKeySomehow();
console.log(myInstance[key]);

And this should work without an error from the compiler, the only problem with that is that the compiler doesn't know the type for the returned value, and it will be any.

So you can do this:

const myInstance = new MyClass(someJson) as MyClass & { [key: string]: string };
let foo = myInstance["foo"]; // type of foo is string
let someProperty = myInstance["someProperty"]; // type of someProperty is boolean

2nd edit

As you do know the props, but not in the class, you can do:

type ExtendedProperties<T> = { [P in keyof T]: T[P] };
function MyClassFactory<T>(json: string): MyClass & ExtendedProperties<T> {
return new MyClass(json) as MyClass & ExtendedProperties<T>;
}

Then you simply use it like so:

type Json = {
foo: string;
bar: string;
};
const myInstance = MyClassFactory<Json>(someJson);

Note that this will work only on typescript 2.1 and above.



Related Topics



Leave a reply



Submit