Setting a property inside a Python method

I want to set a read-only attribute inside a class method.
I already tried this:

class Foo(object): def __init__(self, v): self._set('_v', v) def _set(self, attr, v): setattr(self, attr, v) setattr(Foo, attr[1:], property(lambda self: getattr(self, attr))) 

but it is terrible. Is there another way? I need to set the property:

 class Foo(object): def __init__(self, v): self._v = v @ property def v(self): return self._v >>> f = Foo(42) >>> fv 42 >>> fv = 41 AttributeError: can't set attribute ## This is what I want: a read-only attribute 

but I need to do this inside the method. Is there another way?

Thanks,
Rubik

PS I already checked this post, but it does not solve my problem: Using the Python () property inside a method

EDIT: I cannot use property because I want to set it inside the method. I can use property only from the outside:

 class Foo(object): def __init__(self, v): self._v = v @ property def v(self): return self._v ## ...OR def getv(self): return self._v v = property(getv) 

And I cannot do this because I do not know the name of the property, and I have to set it dynamically. Something like that:

 class Foo(object): def __init__(self, v): self._set_property_from_inside('v', v) >>> f = Foo(42) >>> fv 42 
+4
source share
4 answers

I was thinking about what, in my opinion, is a cleaner solution to implement a pure read-only attribute if that's all you want. This is the solution solution tangentstorm gave, but it generally does not need the __getattr__ method.

 class Foo(object): def __init__(self): self.readonly = set() def set_readonly(self, attr, value): setattr(self, attr, value) self.readonly.add(attr) def __setattr__(self, attr, value): if hasattr(self, "readonly") and attr in self.readonly: raise AttributeError("Read only attribute: %s" % (attr,)) object.__setattr__(self, attr, value) 

It works as follows:

 >>> f = Foo() >>> fx = 5 >>> f.set_readonly("y", 9) >>> fx, fy (5, 9) >>> fx = 7 >>> fy = 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "ro.py", line 13, in __setattr__ raise AttributeError("Read only attribute: %s" % (name,)) AttributeError: Read only attribute: y 

To make the read and write attribute read-only easier:

  def unset_readonly(self, attr): self.readonly.remove(attr) 

In my first attempt to write this idea, I used self.__readonly instead of self.readonly , but this leads to a problem with the actual setting of the __readonly attribute, since I will need to un-munge "private" to check for ( hasattr(self, "_Foo__readonly") ) and this is discouraging.

+1
source

I think you are looking for python descriptors .

 class MyDescriptor(object): def __init__(self, protected_attr_name): self.attr = protected_attr_name def __get__(self, obj, objtype): return getattr(obj, self.attr) def __set__(self, obj, value): #setattr(obj, self.attr, value) raise AttributeError("Can't set attribute") class Foo(object): def __init__(self, k, v): setattr(self.__class__, k, MyDescriptor("_" + k)) setattr(self, "_" + k, v) f = Foo("v", 42) print fv # Prints 42 try: fv = 32 except AttributeError: pass print fv # Prints 42 

Here you can do whatever you want to control access in the __get__ and __set__ . If you call obj.get_v on __get__ and obj.set_v on __set__ , this is very close to the actual implementation of the property, as you can see in the link above.

Change Fixed. I should have read this page better. Citation:

For objects, the mechanism is in object.__getattribute__ , which converts bx to type(b).__dict__['x'].__get__(b, type(b))

Therefore, if you put descriptors in the __dict__ instance, they will simply be overwritten when you set this attribute to a new value.

+3
source
 class Foo(object): def __getattr__(self, name): return getattr(self, "_" + name) def __setattr__(self, name, value): if name.startswith('_'): self.__dict__[name] = value else: raise ValueError("%s is read only" % name) 

Then:

 >>> f = Foo() >>> fx = 5 Traceback (most recent call last): File "<input>", line 1, in <module> File "<input>", line 8, in __setattr__ ValueError: x is read only >>> f._x = 5 >>> fx 5 
+2
source

Property () is exactly the solution. Why not solve your problem? Overriding the setter with the getter method allows you exactly what you need and need: full control over the property.

Please check the official documentation, e.g.

http://docs.python.org/library/functions.html#property

to understand the whole story.

+1
source

Source: https://habr.com/ru/post/895621/


All Articles