The goal is to create a mock class which behaves like a db resultset.
So for example, if a database query returns, using a dict expression, {'ab':100, 'cd':200}
, then I would like to see:
>>> dummy.ab
100
At first I thought maybe I could do it this way:
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
def __init__(self, ks, vs):
for i, k in enumerate(ks):
self[k] = vs[i]
setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))
def fn_readonly(self, v)
raise "It is ready only"
if __name__ == "__main__":
c = C(ks, vs)
print c.ab
but c.ab
returns a property object instead.
Replacing the setattr
line with k = property(lambda x: vs[i])
is of no use at all.
So what is the right way to create an instance property at runtime?
P.S. I am aware of an alternative presented in How is the __getattribute__
method used?
Just another example how to achieve desired effect
So now we can do stuff like:
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.
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 hugeif
tree out of__getattribute__
.When I ask for
foo.b
in the example above, Python sees that theb
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 callsFoo.b.__get__(foo, Foo)
, and the return value is passed back to you as the value of the attribute. In the case ofproperty
, each of these methods just calls thefget
,fset
, orfdel
you passed to theproperty
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
.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: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 readFoo.b
still callsproperty.__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.
This seems to work(but see below):
If you need more complex behavior, feel free to edit your answer.
edit
The following would probably be more memory-efficient for large datasets:
You don't need to use a property for that. Just override
__setattr__
to make them read only.Tada.
It seems you could solve this problem much more simply with a
namedtuple
, since you know the entire list of fields ahead of time.If you absolutely need to write your own setter, you'll have to do the metaprogramming at the class level;
property()
doesn't work on instances.You can use the following code to update class attributes using a dictionary object: