1

I am creating a Python class with a very long list of properties. To avoid boilerplate, I want to define a minimalistic class, and then extend it with my custom properties, which names are provided as a list. However, when I create and add individual properties in a loop, all of them turn out to be identical. What am I missing?

class C(object):
    def _get_item(self, name):
        print(f"I'm getter of {name}")
    def _set_item(self, name, value):
        print(f"I'm setter of {name}")


for item in ['x', 'y', 'z']:
    prop = property(fget = lambda self: self._get_item(item),
                    fset = lambda self, x: self._set_item(item, x))
    setattr(C, item, prop)

o = C()
print(C.x == C.z)   # False
print(C.x is C.z)   # False
o.z                 # I'm getter of z  -  ok
o.y                 # I'm getter of z  -  ??
o.x                 # I'm getter of z  -  ??
o.x = 3             # I'm setter of z  -  ??
o.z = 5             # I'm setter of z  -  ok

Why does the implementation of each property get overridden every time I add a new property? And yet C.x == C.z results in False?

My hypothesis was that they share the same memory, so if I explicitly create a deep copy, I should solve this puzzle. I imported copy and modified line 11 of the script above. However, the output is still the same!

import copy

    ...
# making a deepcopy of the new property
    setattr(C, item, copy.deepcopy(prop))
R Kiselev
  • 1,124
  • 1
  • 9
  • 18
  • 1
    You may have common problem with `lambda` in `for`-loop. When you use `lambda` in `for`-loop then it doesn't get value from `item` but only reference to this object - and it will get value from this reference when `lambda` will be executed. But this way all properties will use reference to the same object in memory which will have last value from `for`-loop - you may need `lambda self, i=item: self._get_item(i)` and `lambda self, x, i=item: self._set_item(i, x)` – furas Jun 26 '22 at 19:22

0 Answers0