-1

Alright, I am rephrasing my question as my motivation wasn't clear enough.

We have a class that users will be populating with properties that are actually implemented using more complex storage/retrieval mechanisms. I've simplified it below. Assume the storage mechanism is just a simple dictionary for now:

class MyClass: def __init__(self, d): self.mydict = d def getterX(self): return self.mydict['X'] def setterX(self, val): self.mydict['X'] = val X = property(getterX, setterX) def getterY(self): return self.mydict['Y'] def setterY(self, val): self.mydict['Y'] = val Y = property(getterY, setterY) da = {} Ma = MyClass(da) Ma.X = 5 Ma.Y = 6 print(Ma.X, Ma.Y) #outputs 5 6 print(da) #outputs {'Y': 6, 'X': 5} 

This works fine, except its quite error prone and verbose. It requires five lines with no less than 7 instances of X that needs to be cut+paste for each new property. Some of these classes may have dozens of properties.

In lieu of using macros (which I don't think Python supports, and is inefficient), I'm trying to simplify this with some helper functions:

da = {} class MyHelper: def __init__(self, dict, label): self.mydict = dict self.mylabel = label def getter2(self, other): return self.mydict[self.mylabel] def setter2(self, other, value): self.mydict[self.mylabel] = value def makeProperty(d, label): H = MyHelper(d, label) return property(H.getter2, H.setter2) class MyClass: def __init__(self, d): self.mydict = d X = makeProperty(da, 'X') #da is global, but should be self.mydict Y = makeProperty(da, 'Y') # " " " Ma = MyClass(da) Ma.X = 5 Ma.Y = 6 print(Ma.X, Ma.Y) #outputs 5 6 print(da) #outputs {'Y': 6, 'X': 5} 

Now this almost works, except calls to makeProperty() need to access a global variable da, instead of using self member data.

This is where I'm stuck, but I'm inclined to believe its possible, given the first code example accesses self member data in its getter/setters.

Hopefully this makes things more clear. Thanks, Rob.

Further information:

I think this solution will not work, as it appears the makeProperty calls are only called once, not once per class instantiation as I was assuming.

So is there any way to make this work, or is the user relegated to much cutting + pasting?

20
  • 2
    what exactly is y supposed to be? Commented Dec 30, 2014 at 22:08
  • I do not understand what you are trying to do here. You can either have the class itself and assign it variables OR assign variables to the class instances. There is no way I can think of that will achieve this (because it doesnt make sense to me). Maybe if you explained in more detail what exactly you are trying to achieve, i could be of more help Commented Dec 30, 2014 at 22:09
  • A property that gets mirrored in a common repository for example. Commented Dec 30, 2014 at 22:09
  • addCustomProperty is undefined also im sure ... since I dont see that anywhere ... Commented Dec 30, 2014 at 22:09
  • 1
    You may want to explain why you need to generate properties in the first place. Commented Dec 30, 2014 at 22:14

1 Answer 1

4

Given the question "Can instances of MyClass each have unique getter/setter functions for property y?", the literal answer is "no" -- descriptors (including property) are looked up on the class, not on the instance.

However, class-level descriptors can delegate to instance-held callables, resulting in a similar effect. Your example is not fully clear to me, but, consider for example:

class Whatever(object): def __init__(self, scale, getter=lambda x: 42): self.scale = scale self.getter = getter @property def y(self): return self.getter(self.scale) plain = Whatever(33) fancy = Whatever(47, lambda x: x*2) 

Now plain.y will be 42, ignoring plain.scale even if that's changed; while fancy.y will initially be 94, but change if and when fancy.scale changes. Is that the kind of thing you're trying to do? It would surely help to see desired use-cases...

Added: given we've seen a simplified use case in a big edit of the Q, here's how I would solve it:

class MyHelper: def __init__(self, label): self.mylabel = label def getter2(self, other): return other.mydict[self.mylabel] def setter2(self, other, value): other.mydict[self.mylabel] = value def makeProperty(label): H = MyHelper(label) return property(H.getter2, H.setter2) class MyClass: def __init__(self, d): self.mydict = d X = makeProperty('X') Y = makeProperty('Y') 

The factory-function makeProperty could be elided by changing the names of MyHelper's methods to __get__ and __set__ (i.e, making MyHelper itself into a descriptor type) and calling MyHelper directly to build its instances to be assigned, but this slightly less direct approach may perhaps be easier to understand as it relies on the well-known built-in type property.

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

2 Comments

Hi I've rephrased my question entirely above for clarity. I'm not certain if your information is still applicable. Thanks for your input.
Yes thank you, it occurred to me this morning, I did not need to pass in self to makeProperty, as it would be available as the 'other' argument in the getter/setter calls. Thank you for confirming and providing extra explanation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.