I want to create a class in python that has setters for its attributes.
For example suppose we have a class named myClass and it has x attribute. I want to create it so that when someone changes x value, only two last digits of x (x % 100) are saved.
using myClass in python shell:
>>> obj = myClass()
>>> obj.x = 352562
>>> obj.x
62
Can I define a setter that is called automatically when changing the value of x?
You can use properties decorators
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value % 100
Also you will have to declare and initialise _x in your init method for a safer code
See this stack overflow post for more information
Related
I'm confused with how attribute variables are behaving in my class when using the property decorator.
See this example:
class Example:
def __init__(self, x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
self.__x = x
This works fine, but how? The variable inside the setter property (self.__x) has not been "defined" in the constructor, so how can it be assigned a value?
Other stuff also works, for example, take the same class defined above and add a new member function to it:
def set_val_x(self):
self.__x = 8765
Again, using this function actually works, similar to the property.setter (but it's not using the property decorator).
Inside __init__, the line
self.x = x
is no longer short for
setattr(self, 'x', x)
because the class attribute Example.x exists. You are no longer creating an instance attribute x, but calling
type(self).X.__set__(self, 'x', x)
which will set the instance attribute __x.
Instance attributes can be created, modified, or deleted at any time. The __init__ method is just a convenient, single place to create them because it is called for you automatically every time you create an instance.
In Python, you don’t have to define variables in the constructor. You can assign them whenever you want.
class Foo:
def __init__(self, bar):
self.bar = bar
my_foo = Foo(3)
my_foo.other_thing = 6
is perfectly legal, for example.
How can I check if an attribute of an object has been set by the user or not? Currently, I have a class
class foo:
def __init__(self):
self.bar = 'baz'
Later I would like to check if the user set the value of bar or not, i.e. with something like
my_foo = foo()
my_foo.bar = 'mybaz'
so I would like to know if the second line above has been called or not (to throw a warning if it has not). I have two solutions, but I don't like either of them:
Check if my_foo.bar is equal to the default value. But it could be that the user sets my_foo.bar to the same value and then I don't want to throw a warning.
Don't set the default value in __init__, but only when it is used. Then it can be checked with getattr() and set with setattr().
I'm sure there is an elegant pythonic way to do it that I haven't thought of.
Use the #property decorator to construct getters and setters, and the make the setter tell you when a user changes the attribute, example below
class Foo:
def __init__(self):
self._x_was_modified = False
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x_was_modified = True
self._x = value
foo = Foo()
print('x was modified by user: {}'.format(foo._x_was_modified))
foo.x = 42
print('x was modified by user: {}'.format(foo._x_was_modified))
This will output:
x was modified by user: False
x was modified by user: True
Another solution that again involves using a flag is done by playing around with the __setattr__ method:
class foo:
def __init__(self):
self._altered = -1
self.bar = 'baz'
def __setattr__(self, attrname, val):
if attrname is 'bar':
self._altered += 1
super.__setattr__(self, attrname, val)
# if you heard super is evil and you feel
# funny using it in your code instead use:
# object.__setattr__(self, attrname, val)
If somebody re-sets this variable the value of self._altered will be positive and as a result evaluate to True (remember, first access is made in __init__ during initialization and increments _altered once).
After this you can make a nice intuitive check of the form:
f = foo()
f.bar = "booz" # now f._altered == 1
if f._altered: raise MyAlcoholicException
and be done. Just another way of doing practically the same exact thing.
I am generally confused about the difference between a "property" and an "attribute", and can't find a great resource to concisely detail the differences.
Properties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs in spam, and then examines eggs to see if it has a __get__, __set__, or __delete__ method — if it does, it's a property. If it is a property, instead of just returning the eggs object (as it would for any other attribute) it will call the __get__ method (since we were doing lookup) and return whatever that method returns.
More information about Python's data model and descriptors.
With a property you have complete control on its getter, setter and deleter methods, which you don't have (if not using caveats) with an attribute.
class A(object):
_x = 0
'''A._x is an attribute'''
#property
def x(self):
'''
A.x is a property
This is the getter method
'''
return self._x
#x.setter
def x(self, value):
"""
This is the setter method
where I can check it's not assigned a value < 0
"""
if value < 0:
raise ValueError("Must be >= 0")
self._x = value
>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
File "ex.py", line 15, in <module>
a.x = -1
File "ex.py", line 9, in x
raise ValueError("Must be >= 0")
ValueError: Must be >= 0
In general speaking terms a property and an attribute are the same thing. However, there is a property decorator in Python which provides getter/setter access to an attribute (or other data).
class MyObject(object):
# This is a normal attribute
foo = 1
#property
def bar(self):
return self.foo
#bar.setter
def bar(self, value):
self.foo = value
obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo
The property allows you to get and set values like you would normal attributes, but underneath there is a method being called translating it into a getter and setter for you. It's really just a convenience to cut down on the boilerplate of calling getters and setters.
Lets say for example, you had a class that held some x and y coordinates for something you needed. To set them you might want to do something like:
myObj.x = 5
myObj.y = 10
That is much easier to look at and think about than writing:
myObj.setX(5)
myObj.setY(10)
The problem is, what if one day your class changes such that you need to offset your x and y by some value? Now you would need to go in and change your class definition and all of the code that calls it, which could be really time consuming and error prone. The property allows you to use the former syntax while giving you the flexibility of change of the latter.
In Python, you can define getters, setters, and delete methods with the property function. If you just want the read property, there is also a #property decorator you can add above your method.
http://docs.python.org/library/functions.html#property
I learnt 2 differences from site of Bernd Klein, in summary:
1. A property is a more convenient way to achieve data encapsulation
For example, let's say you have a public attribute length. Later on, your project requires you to encapsulate it, i.e. to change it to private and provide a getter and setter => you have to change the the code you wrote before:
# Old code
obj1.length = obj1.length + obj2.length
# New code (using private attributes and getter and setter)
obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly
If you use #property and #length.setter => you don't need to change that old code.
2. A property can encapsulate multiple attributes
class Person:
def __init__(self, name, physic_health, mental_health):
self.name = name
self.__physic_health = physic_health
self.__mental_health = mental_health
#property
def condition(self):
health = self.__physic_health + self.__mental_health
if(health < 5.0):
return "I feel bad!"
elif health < 8.0:
return "I am ok!"
else:
return "Great!"
In this example, __physic_health and __mental_health are private and cannot be accessed directly from outside.
There is also one not obvious difference that i use to cache or refresh data , often we have a function connected to class attribute. For instance i need to read file once and keep content assigned to the attribute so the value is cached:
class Misc():
def __init__(self):
self.test = self.test_func()
def test_func(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func value
We accessed the attribute twice but our function was fired only once. Changing the above example to use property will cause attribute's value refresh each time you access it:
class Misc():
#property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func running
func value
I like to think that, if you want to set a restriction for an attribute, use a property.
Although all attributes are public, generally programmers differentiate public and private attributes with an underscore(_). Consider the following class,
class A:
def __init__(self):
self.b = 3 # To show public
self._c = 4 # To show private
Here, b attribute is intended to be accessed from outside class A. But, readers of this class might wonder, can b attribute be set from outside class A?
If we intend to not set b from outside, we can show this intention with #property.
class A:
def __init__(self):
self._c = 4 # To show private
#property
def b(self):
return 3
Now, b can't be set.
a = A()
print(a.b) # prints 3
a.b = 7 # Raises AttributeError
Or, if you wish to set only certain values,
class A:
#property
def b(self):
return self._b
#b.setter
def b(self, val):
if val < 0:
raise ValueError("b can't be negative")
self._b = val
a = A()
a.b = 6 # OK
a.b = -5 # Raises ValueError
I am generally confused about the difference between a "property" and an "attribute", and can't find a great resource to concisely detail the differences.
Properties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs in spam, and then examines eggs to see if it has a __get__, __set__, or __delete__ method — if it does, it's a property. If it is a property, instead of just returning the eggs object (as it would for any other attribute) it will call the __get__ method (since we were doing lookup) and return whatever that method returns.
More information about Python's data model and descriptors.
With a property you have complete control on its getter, setter and deleter methods, which you don't have (if not using caveats) with an attribute.
class A(object):
_x = 0
'''A._x is an attribute'''
#property
def x(self):
'''
A.x is a property
This is the getter method
'''
return self._x
#x.setter
def x(self, value):
"""
This is the setter method
where I can check it's not assigned a value < 0
"""
if value < 0:
raise ValueError("Must be >= 0")
self._x = value
>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
File "ex.py", line 15, in <module>
a.x = -1
File "ex.py", line 9, in x
raise ValueError("Must be >= 0")
ValueError: Must be >= 0
In general speaking terms a property and an attribute are the same thing. However, there is a property decorator in Python which provides getter/setter access to an attribute (or other data).
class MyObject(object):
# This is a normal attribute
foo = 1
#property
def bar(self):
return self.foo
#bar.setter
def bar(self, value):
self.foo = value
obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo
The property allows you to get and set values like you would normal attributes, but underneath there is a method being called translating it into a getter and setter for you. It's really just a convenience to cut down on the boilerplate of calling getters and setters.
Lets say for example, you had a class that held some x and y coordinates for something you needed. To set them you might want to do something like:
myObj.x = 5
myObj.y = 10
That is much easier to look at and think about than writing:
myObj.setX(5)
myObj.setY(10)
The problem is, what if one day your class changes such that you need to offset your x and y by some value? Now you would need to go in and change your class definition and all of the code that calls it, which could be really time consuming and error prone. The property allows you to use the former syntax while giving you the flexibility of change of the latter.
In Python, you can define getters, setters, and delete methods with the property function. If you just want the read property, there is also a #property decorator you can add above your method.
http://docs.python.org/library/functions.html#property
I learnt 2 differences from site of Bernd Klein, in summary:
1. A property is a more convenient way to achieve data encapsulation
For example, let's say you have a public attribute length. Later on, your project requires you to encapsulate it, i.e. to change it to private and provide a getter and setter => you have to change the the code you wrote before:
# Old code
obj1.length = obj1.length + obj2.length
# New code (using private attributes and getter and setter)
obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly
If you use #property and #length.setter => you don't need to change that old code.
2. A property can encapsulate multiple attributes
class Person:
def __init__(self, name, physic_health, mental_health):
self.name = name
self.__physic_health = physic_health
self.__mental_health = mental_health
#property
def condition(self):
health = self.__physic_health + self.__mental_health
if(health < 5.0):
return "I feel bad!"
elif health < 8.0:
return "I am ok!"
else:
return "Great!"
In this example, __physic_health and __mental_health are private and cannot be accessed directly from outside.
There is also one not obvious difference that i use to cache or refresh data , often we have a function connected to class attribute. For instance i need to read file once and keep content assigned to the attribute so the value is cached:
class Misc():
def __init__(self):
self.test = self.test_func()
def test_func(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func value
We accessed the attribute twice but our function was fired only once. Changing the above example to use property will cause attribute's value refresh each time you access it:
class Misc():
#property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func running
func value
I like to think that, if you want to set a restriction for an attribute, use a property.
Although all attributes are public, generally programmers differentiate public and private attributes with an underscore(_). Consider the following class,
class A:
def __init__(self):
self.b = 3 # To show public
self._c = 4 # To show private
Here, b attribute is intended to be accessed from outside class A. But, readers of this class might wonder, can b attribute be set from outside class A?
If we intend to not set b from outside, we can show this intention with #property.
class A:
def __init__(self):
self._c = 4 # To show private
#property
def b(self):
return 3
Now, b can't be set.
a = A()
print(a.b) # prints 3
a.b = 7 # Raises AttributeError
Or, if you wish to set only certain values,
class A:
#property
def b(self):
return self._b
#b.setter
def b(self, val):
if val < 0:
raise ValueError("b can't be negative")
self._b = val
a = A()
a.b = 6 # OK
a.b = -5 # Raises ValueError
I'm trying to use new-style properties declaration:
class C(object):
def __init__(self):
self._x = 0
#property
def x(self):
print 'getting'
return self._x
#x.setter
def set_x(self, value):
print 'setting'
self._x = value
if __name__ == '__main__':
c = C()
print c.x
c.x = 10
print c.x
and see the following in console:
pydev debugger: starting
getting
0
File "\test.py", line 55, in <module>
c.x = 10
AttributeError: can't set attribute
what am I doing wrong?
P.S.: Old-style declaration works fine.
The documentation says the following about using decorator form of property:
Be sure to give the additional functions the same name as the original property (x in this case.)
I have no idea why this is since if you use property as function to return an attribute the methods can be called whatever you like.
So you need to change your code to the following:
#x.setter
def x(self, value):
'setting'
self._x = value
The setter method has to have the same name as the getter. Don't worry, the decorator knows how to tell them apart.
#x.setter
def x(self, value):
...
When you call #x.setter, #x.getter, or #x.deleter, you're creating a new property object and giving it the name of the function you're decorating. So really, all that matters is that the last time you use a #x.*er decorator in the class definition, it has the name you actually want to use. But since this would leave your class namespace polluted with incomplete versions of the property you wish to use, it's best to use the same name to clean them up.
If you don't want the extra _x name slot, here's a complex little trick you can do:
(tested with Py34)
>>> class C(object):
__slots__ = ['x'] # create a member_descriptor
def __init__( self ):
self.x = 0
# or use this if you don't want to call x_setter:
#set_x( self, 0 )
>>> get_x = C.x.__get__ # member_descriptor getter
>>> set_x = C.x.__set__ # member_descriptor setter
>>> # define custom wrappers:
>>> def x_getter( self ):
print('getting')
return get_x( self )
>>> def x_setter( self, value ):
print('setting')
set_x( self, value )
>>> C.x = property( x_getter, x_setter ) # replace the member_descriptor
>>> c = C()
setting
>>> print(c.x)
getting
0
>>> c.x = 10
setting
>>>