nesting of properties vs setters and getters in python - python

class OurAtt():
def __init__(self):
self.Log = False
def setLog(self):
self.Log = True
def clearLog(self):
self.Log = False
class OurClass(object):
def __init__(self):
self.__OurAtt = OurAtt()
#property
def OurAtt(self):
return self.__OurAtt
#OurAtt.setter
def OurAtt(self, val):
raise Exception("can't modify the attribute" )
x = OurClass()
x.OurAtt.setLog()
print x.OurAtt.Log # print True
x.OurAtt.Log = False
print x.OurAtt.Log # sets to False Aim set this through function call x.OurAtt.setLog() I want to restrict the access, something like private variable.
Final aim is Log should be the attribute of OurAttr and should be protected by getter and setters or properties. Its like nesting of properties. and hierarchy should be maintained like object.OurAttr.Log
I researched and got the following link.
Python: multiple properties, one setter/getter
But It is not hitting my aim.
I am actually new to getter, setter and properties. Thanks in advance

I believe you are over-complicating the issue. If you want to prevent access to the attributes of OurAtt, the #property decorator should be used withing OurAtt. Instances of the OurAtt class will implement this protected-access behavior always, including when they are members of OurClass. You don't need to do anything with the #property decorator in OurClass unless you want to prevent modifying members of that class.
This, I think, does what you are trying to accomplish. It runs under 2.7 - if you are using an earlier version your mileage may vary.
class OurAttr(object):
def __init__(self):
self._log = False
#property
def log(self):
return self._log
#log.setter
def log(self, value):
raise AttributeError("Cannot set 'log' attribute directly.")
#log.deleter
def log(self):
raise AttributeError("Cannot delete 'log' attribute directly.")
def setLog(self):
self._log = True
print "Log is", self._log
def clearLog(self):
self._log = False
print "Log is", self._log
class OurClass(object):
def __init__(self):
self.OurAttr = OurAttr()
oc = OurClass()
oc.OurAttr.setLog()
oc.OurAttr.clearLog()
oc.OurAttr.log = False # Raises exception
Output is:
$ python2.7 test.py
Log is True
Log is False
Traceback (most recent call last):
File "test.py", line 33, in <module>
oc.OurAttr.log = False
File "test.py", line 11, in log
raise AttributeError("Cannot set 'log' attribute directly.")
AttributeError: Cannot set 'log' attribute directly.

Related

which one is preferable to use in oop: property definition or method definition [duplicate]

I'm doing it like:
def set_property(property,value):
def get_property(property):
or
object.property = value
value = object.property
What's the pythonic way to use getters and setters?
Try this: Python Property
The sample code is:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
print("getter of x called")
return self._x
#x.setter
def x(self, value):
print("setter of x called")
self._x = value
#x.deleter
def x(self):
print("deleter of x called")
del self._x
c = C()
c.x = 'foo' # setter called
foo = c.x # getter called
del c.x # deleter called
What's the pythonic way to use getters and setters?
The "Pythonic" way is not to use "getters" and "setters", but to use plain attributes, like the question demonstrates, and del for deleting (but the names are changed to protect the innocent... builtins):
value = 'something'
obj.attribute = value
value = obj.attribute
del obj.attribute
If later, you want to modify the setting and getting, you can do so without having to alter user code, by using the property decorator:
class Obj:
"""property demo"""
#
#property # first decorate the getter method
def attribute(self): # This getter method name is *the* name
return self._attribute
#
#attribute.setter # the property decorates with `.setter` now
def attribute(self, value): # name, e.g. "attribute", is the same
self._attribute = value # the "value" name isn't special
#
#attribute.deleter # decorate with `.deleter`
def attribute(self): # again, the method name is the same
del self._attribute
(Each decorator usage copies and updates the prior property object, so note that you should use the same name for each set, get, and delete function/method.)
After defining the above, the original setting, getting, and deleting code is the same:
obj = Obj()
obj.attribute = value
the_value = obj.attribute
del obj.attribute
You should avoid this:
def set_property(property,value):
def get_property(property):
Firstly, the above doesn't work, because you don't provide an argument for the instance that the property would be set to (usually self), which would be:
class Obj:
def set_property(self, property, value): # don't do this
...
def get_property(self, property): # don't do this either
...
Secondly, this duplicates the purpose of two special methods, __setattr__ and __getattr__.
Thirdly, we also have the setattr and getattr builtin functions.
setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value) # default is optional
The #property decorator is for creating getters and setters.
For example, we could modify the setting behavior to place restrictions the value being set:
class Protective(object):
#property
def protected_value(self):
return self._protected_value
#protected_value.setter
def protected_value(self, value):
if acceptable(value): # e.g. type or range check
self._protected_value = value
In general, we want to avoid using property and just use direct attributes.
This is what is expected by users of Python. Following the rule of least-surprise, you should try to give your users what they expect unless you have a very compelling reason to the contrary.
Demonstration
For example, say we needed our object's protected attribute to be an integer between 0 and 100 inclusive, and prevent its deletion, with appropriate messages to inform the user of its proper usage:
class Protective(object):
"""protected property demo"""
#
def __init__(self, start_protected_value=0):
self.protected_value = start_protected_value
#
#property
def protected_value(self):
return self._protected_value
#
#protected_value.setter
def protected_value(self, value):
if value != int(value):
raise TypeError("protected_value must be an integer")
if 0 <= value <= 100:
self._protected_value = int(value)
else:
raise ValueError("protected_value must be " +
"between 0 and 100 inclusive")
#
#protected_value.deleter
def protected_value(self):
raise AttributeError("do not delete, protected_value can be set to 0")
(Note that __init__ refers to self.protected_value but the property methods refer to self._protected_value. This is so that __init__ uses the property through the public API, ensuring it is "protected".)
And usage:
>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0
Do the names matter?
Yes they do. .setter and .deleter make copies of the original property. This allows subclasses to properly modify behavior without altering the behavior in the parent.
class Obj:
"""property demo"""
#
#property
def get_only(self):
return self._attribute
#
#get_only.setter
def get_or_set(self, value):
self._attribute = value
#
#get_or_set.deleter
def get_set_or_delete(self):
del self._attribute
Now for this to work, you have to use the respective names:
obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error
I'm not sure where this would be useful, but the use-case is if you want a get, set, and/or delete-only property. Probably best to stick to semantically same property having the same name.
Conclusion
Start with simple attributes.
If you later need functionality around the setting, getting, and deleting, you can add it with the property decorator.
Avoid functions named set_... and get_... - that's what properties are for.
In [1]: class test(object):
def __init__(self):
self.pants = 'pants'
#property
def p(self):
return self.pants
#p.setter
def p(self, value):
self.pants = value * 2
....:
In [2]: t = test()
In [3]: t.p
Out[3]: 'pants'
In [4]: t.p = 10
In [5]: t.p
Out[5]: 20
Using #property and #attribute.setter helps you to not only use the "pythonic" way but also to check the validity of attributes both while creating the object and when altering it.
class Person(object):
def __init__(self, p_name=None):
self.name = p_name
#property
def name(self):
return self._name
#name.setter
def name(self, new_name):
if type(new_name) == str: #type checking for name property
self._name = new_name
else:
raise Exception("Invalid value for name")
By this, you actually 'hide' _name attribute from client developers and also perform checks on name property type. Note that by following this approach even during the initiation the setter gets called. So:
p = Person(12)
Will lead to:
Exception: Invalid value for name
But:
>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
This is an old question but the topic is very important and always current. In case anyone wants to go beyond simple getters/setters i have wrote an article about superpowered properties in python with support for slots, observability and reduced boilerplate code.
from objects import properties, self_properties
class Car:
with properties(locals(), 'meta') as meta:
#meta.prop(read_only=True)
def brand(self) -> str:
"""Brand"""
#meta.prop(read_only=True)
def max_speed(self) -> float:
"""Maximum car speed"""
#meta.prop(listener='_on_acceleration')
def speed(self) -> float:
"""Speed of the car"""
return 0 # Default stopped
#meta.prop(listener='_on_off_listener')
def on(self) -> bool:
"""Engine state"""
return False
def __init__(self, brand: str, max_speed: float = 200):
self_properties(self, locals())
def _on_off_listener(self, prop, old, on):
if on:
print(f"{self.brand} Turned on, Runnnnnn")
else:
self._speed = 0
print(f"{self.brand} Turned off.")
def _on_acceleration(self, prop, old, speed):
if self.on:
if speed > self.max_speed:
print(f"{self.brand} {speed}km/h Bang! Engine exploded!")
self.on = False
else:
print(f"{self.brand} New speed: {speed}km/h")
else:
print(f"{self.brand} Car is off, no speed change")
This class can be used like this:
mycar = Car('Ford')
# Car is turned off
for speed in range(0, 300, 50):
mycar.speed = speed
# Car is turned on
mycar.on = True
for speed in range(0, 350, 50):
mycar.speed = speed
This code will produce the following output:
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Turned on, Runnnnnn
Ford New speed: 0km/h
Ford New speed: 50km/h
Ford New speed: 100km/h
Ford New speed: 150km/h
Ford New speed: 200km/h
Ford 250km/h Bang! Engine exploded!
Ford Turned off.
Ford Car is off, no speed change
More info about how and why here: https://mnesarco.github.io/blog/2020/07/23/python-metaprogramming-properties-on-steroids
Properties are pretty useful since you can use them with assignment but then can include validation as well. You can see this code where you use the decorator #property and also #<property_name>.setter to create the methods:
# Python program displaying the use of #property
class AgeSet:
def __init__(self):
self._age = 0
# using property decorator a getter function
#property
def age(self):
print("getter method called")
return self._age
# a setter function
#age.setter
def age(self, a):
if(a < 18):
raise ValueError("Sorry your age is below eligibility criteria")
print("setter method called")
self._age = a
pkj = AgeSet()
pkj.age = int(input("set the age using setter: "))
print(pkj.age)
There are more details in this post I wrote about this as well: https://pythonhowtoprogram.com/how-to-create-getter-setter-class-properties-in-python-3/
You can use accessors/mutators (i.e. #attr.setter and #property) or not, but the most important thing is to be consistent!
If you're using #property to simply access an attribute, e.g.
class myClass:
def __init__(a):
self._a = a
#property
def a(self):
return self._a
use it to access every* attribute! It would be a bad practice to access some attributes using #property and leave some other properties public (i.e. name without an underscore) without an accessor, e.g. do not do
class myClass:
def __init__(a, b):
self.a = a
self.b = b
#property
def a(self):
return self.a
Note that self.b does not have an explicit accessor here even though it's public.
Similarly with setters (or mutators), feel free to use #attribute.setter but be consistent! When you do e.g.
class myClass:
def __init__(a, b):
self.a = a
self.b = b
#a.setter
def a(self, value):
return self.a = value
It's hard for me to guess your intention. On one hand you're saying that both a and b are public (no leading underscore in their names) so I should theoretically be allowed to access/mutate (get/set) both. But then you specify an explicit mutator only for a, which tells me that maybe I should not be able to set b. Since you've provided an explicit mutator I am not sure if the lack of explicit accessor (#property) means I should not be able to access either of those variables or you were simply being frugal in using #property.
*The exception is when you explicitly want to make some variables accessible or mutable but not both or you want to perform some additional logic when accessing or mutating an attribute. This is when I am personally using #property and #attribute.setter (otherwise no explicit acessors/mutators for public attributes).
Lastly, PEP8 and Google Style Guide suggestions:
PEP8, Designing for Inheritance says:
For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.
On the other hand, according to Google Style Guide Python Language Rules/Properties the recommendation is to:
Use properties in new code to access or set data where you would normally have used simple, lightweight accessor or setter methods. Properties should be created with the #property decorator.
The pros of this approach:
Readability is increased by eliminating explicit get and set method calls for simple attribute access. Allows calculations to be lazy. Considered the Pythonic way to maintain the interface of a class. In terms of performance, allowing properties bypasses needing trivial accessor methods when a direct variable access is reasonable. This also allows accessor methods to be added in the future without breaking the interface.
and cons:
Must inherit from object in Python 2. Can hide side-effects much like operator overloading. Can be confusing for subclasses.
You can use the magic methods __getattribute__ and __setattr__.
class MyClass:
def __init__(self, attrvalue):
self.myattr = attrvalue
def __getattribute__(self, attr):
if attr == "myattr":
#Getter for myattr
def __setattr__(self, attr):
if attr == "myattr":
#Setter for myattr
Be aware that __getattr__ and __getattribute__ are not the same. __getattr__ is only invoked when the attribute is not found.

Why setting some attributes of a class is not possible?

I tried to create my own dummy response inherited from requests.Response. It would add an extra attribute and overwrite an existing one:
import requests
class MyResponse(requests.Response):
def __init__(self):
super().__init__()
self.hello = "world"
self.ok = False
print(vars(MyResponse()))
Adding self.hello is fine, but when I want to force self.ok to a value I get:
Traceback (most recent call last):
File "C:/Users/yop/.PyCharm2019.2/config/scratches/scratch.py", line 11, in <module>
print(vars(MyResponse()))
File "C:/Users/yop/.PyCharm2019.2/config/scratches/scratch.py", line 9, in __init__
self.ok = False
AttributeError: can't set attribute
Why are there some attributes which cannot be set/overwritten?
ok is a property of requests.Response but it has no setter so it can't be set.
Instead, you can override it and always return False (or True or whatever you want):
class MyResponse(requests.Response):
def __init__(self):
super().__init__()
self.hello = "world"
#property
def ok(self):
return False
Alternatively, look at a proper mocking solution such as the mock module.

Python property in __init__ with double assignment [duplicate]

I'm doing it like:
def set_property(property,value):
def get_property(property):
or
object.property = value
value = object.property
What's the pythonic way to use getters and setters?
Try this: Python Property
The sample code is:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
print("getter of x called")
return self._x
#x.setter
def x(self, value):
print("setter of x called")
self._x = value
#x.deleter
def x(self):
print("deleter of x called")
del self._x
c = C()
c.x = 'foo' # setter called
foo = c.x # getter called
del c.x # deleter called
What's the pythonic way to use getters and setters?
The "Pythonic" way is not to use "getters" and "setters", but to use plain attributes, like the question demonstrates, and del for deleting (but the names are changed to protect the innocent... builtins):
value = 'something'
obj.attribute = value
value = obj.attribute
del obj.attribute
If later, you want to modify the setting and getting, you can do so without having to alter user code, by using the property decorator:
class Obj:
"""property demo"""
#
#property # first decorate the getter method
def attribute(self): # This getter method name is *the* name
return self._attribute
#
#attribute.setter # the property decorates with `.setter` now
def attribute(self, value): # name, e.g. "attribute", is the same
self._attribute = value # the "value" name isn't special
#
#attribute.deleter # decorate with `.deleter`
def attribute(self): # again, the method name is the same
del self._attribute
(Each decorator usage copies and updates the prior property object, so note that you should use the same name for each set, get, and delete function/method.)
After defining the above, the original setting, getting, and deleting code is the same:
obj = Obj()
obj.attribute = value
the_value = obj.attribute
del obj.attribute
You should avoid this:
def set_property(property,value):
def get_property(property):
Firstly, the above doesn't work, because you don't provide an argument for the instance that the property would be set to (usually self), which would be:
class Obj:
def set_property(self, property, value): # don't do this
...
def get_property(self, property): # don't do this either
...
Secondly, this duplicates the purpose of two special methods, __setattr__ and __getattr__.
Thirdly, we also have the setattr and getattr builtin functions.
setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value) # default is optional
The #property decorator is for creating getters and setters.
For example, we could modify the setting behavior to place restrictions the value being set:
class Protective(object):
#property
def protected_value(self):
return self._protected_value
#protected_value.setter
def protected_value(self, value):
if acceptable(value): # e.g. type or range check
self._protected_value = value
In general, we want to avoid using property and just use direct attributes.
This is what is expected by users of Python. Following the rule of least-surprise, you should try to give your users what they expect unless you have a very compelling reason to the contrary.
Demonstration
For example, say we needed our object's protected attribute to be an integer between 0 and 100 inclusive, and prevent its deletion, with appropriate messages to inform the user of its proper usage:
class Protective(object):
"""protected property demo"""
#
def __init__(self, start_protected_value=0):
self.protected_value = start_protected_value
#
#property
def protected_value(self):
return self._protected_value
#
#protected_value.setter
def protected_value(self, value):
if value != int(value):
raise TypeError("protected_value must be an integer")
if 0 <= value <= 100:
self._protected_value = int(value)
else:
raise ValueError("protected_value must be " +
"between 0 and 100 inclusive")
#
#protected_value.deleter
def protected_value(self):
raise AttributeError("do not delete, protected_value can be set to 0")
(Note that __init__ refers to self.protected_value but the property methods refer to self._protected_value. This is so that __init__ uses the property through the public API, ensuring it is "protected".)
And usage:
>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0
Do the names matter?
Yes they do. .setter and .deleter make copies of the original property. This allows subclasses to properly modify behavior without altering the behavior in the parent.
class Obj:
"""property demo"""
#
#property
def get_only(self):
return self._attribute
#
#get_only.setter
def get_or_set(self, value):
self._attribute = value
#
#get_or_set.deleter
def get_set_or_delete(self):
del self._attribute
Now for this to work, you have to use the respective names:
obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error
I'm not sure where this would be useful, but the use-case is if you want a get, set, and/or delete-only property. Probably best to stick to semantically same property having the same name.
Conclusion
Start with simple attributes.
If you later need functionality around the setting, getting, and deleting, you can add it with the property decorator.
Avoid functions named set_... and get_... - that's what properties are for.
In [1]: class test(object):
def __init__(self):
self.pants = 'pants'
#property
def p(self):
return self.pants
#p.setter
def p(self, value):
self.pants = value * 2
....:
In [2]: t = test()
In [3]: t.p
Out[3]: 'pants'
In [4]: t.p = 10
In [5]: t.p
Out[5]: 20
Using #property and #attribute.setter helps you to not only use the "pythonic" way but also to check the validity of attributes both while creating the object and when altering it.
class Person(object):
def __init__(self, p_name=None):
self.name = p_name
#property
def name(self):
return self._name
#name.setter
def name(self, new_name):
if type(new_name) == str: #type checking for name property
self._name = new_name
else:
raise Exception("Invalid value for name")
By this, you actually 'hide' _name attribute from client developers and also perform checks on name property type. Note that by following this approach even during the initiation the setter gets called. So:
p = Person(12)
Will lead to:
Exception: Invalid value for name
But:
>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
This is an old question but the topic is very important and always current. In case anyone wants to go beyond simple getters/setters i have wrote an article about superpowered properties in python with support for slots, observability and reduced boilerplate code.
from objects import properties, self_properties
class Car:
with properties(locals(), 'meta') as meta:
#meta.prop(read_only=True)
def brand(self) -> str:
"""Brand"""
#meta.prop(read_only=True)
def max_speed(self) -> float:
"""Maximum car speed"""
#meta.prop(listener='_on_acceleration')
def speed(self) -> float:
"""Speed of the car"""
return 0 # Default stopped
#meta.prop(listener='_on_off_listener')
def on(self) -> bool:
"""Engine state"""
return False
def __init__(self, brand: str, max_speed: float = 200):
self_properties(self, locals())
def _on_off_listener(self, prop, old, on):
if on:
print(f"{self.brand} Turned on, Runnnnnn")
else:
self._speed = 0
print(f"{self.brand} Turned off.")
def _on_acceleration(self, prop, old, speed):
if self.on:
if speed > self.max_speed:
print(f"{self.brand} {speed}km/h Bang! Engine exploded!")
self.on = False
else:
print(f"{self.brand} New speed: {speed}km/h")
else:
print(f"{self.brand} Car is off, no speed change")
This class can be used like this:
mycar = Car('Ford')
# Car is turned off
for speed in range(0, 300, 50):
mycar.speed = speed
# Car is turned on
mycar.on = True
for speed in range(0, 350, 50):
mycar.speed = speed
This code will produce the following output:
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Car is off, no speed change
Ford Turned on, Runnnnnn
Ford New speed: 0km/h
Ford New speed: 50km/h
Ford New speed: 100km/h
Ford New speed: 150km/h
Ford New speed: 200km/h
Ford 250km/h Bang! Engine exploded!
Ford Turned off.
Ford Car is off, no speed change
More info about how and why here: https://mnesarco.github.io/blog/2020/07/23/python-metaprogramming-properties-on-steroids
Properties are pretty useful since you can use them with assignment but then can include validation as well. You can see this code where you use the decorator #property and also #<property_name>.setter to create the methods:
# Python program displaying the use of #property
class AgeSet:
def __init__(self):
self._age = 0
# using property decorator a getter function
#property
def age(self):
print("getter method called")
return self._age
# a setter function
#age.setter
def age(self, a):
if(a < 18):
raise ValueError("Sorry your age is below eligibility criteria")
print("setter method called")
self._age = a
pkj = AgeSet()
pkj.age = int(input("set the age using setter: "))
print(pkj.age)
There are more details in this post I wrote about this as well: https://pythonhowtoprogram.com/how-to-create-getter-setter-class-properties-in-python-3/
You can use accessors/mutators (i.e. #attr.setter and #property) or not, but the most important thing is to be consistent!
If you're using #property to simply access an attribute, e.g.
class myClass:
def __init__(a):
self._a = a
#property
def a(self):
return self._a
use it to access every* attribute! It would be a bad practice to access some attributes using #property and leave some other properties public (i.e. name without an underscore) without an accessor, e.g. do not do
class myClass:
def __init__(a, b):
self.a = a
self.b = b
#property
def a(self):
return self.a
Note that self.b does not have an explicit accessor here even though it's public.
Similarly with setters (or mutators), feel free to use #attribute.setter but be consistent! When you do e.g.
class myClass:
def __init__(a, b):
self.a = a
self.b = b
#a.setter
def a(self, value):
return self.a = value
It's hard for me to guess your intention. On one hand you're saying that both a and b are public (no leading underscore in their names) so I should theoretically be allowed to access/mutate (get/set) both. But then you specify an explicit mutator only for a, which tells me that maybe I should not be able to set b. Since you've provided an explicit mutator I am not sure if the lack of explicit accessor (#property) means I should not be able to access either of those variables or you were simply being frugal in using #property.
*The exception is when you explicitly want to make some variables accessible or mutable but not both or you want to perform some additional logic when accessing or mutating an attribute. This is when I am personally using #property and #attribute.setter (otherwise no explicit acessors/mutators for public attributes).
Lastly, PEP8 and Google Style Guide suggestions:
PEP8, Designing for Inheritance says:
For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.
On the other hand, according to Google Style Guide Python Language Rules/Properties the recommendation is to:
Use properties in new code to access or set data where you would normally have used simple, lightweight accessor or setter methods. Properties should be created with the #property decorator.
The pros of this approach:
Readability is increased by eliminating explicit get and set method calls for simple attribute access. Allows calculations to be lazy. Considered the Pythonic way to maintain the interface of a class. In terms of performance, allowing properties bypasses needing trivial accessor methods when a direct variable access is reasonable. This also allows accessor methods to be added in the future without breaking the interface.
and cons:
Must inherit from object in Python 2. Can hide side-effects much like operator overloading. Can be confusing for subclasses.
You can use the magic methods __getattribute__ and __setattr__.
class MyClass:
def __init__(self, attrvalue):
self.myattr = attrvalue
def __getattribute__(self, attr):
if attr == "myattr":
#Getter for myattr
def __setattr__(self, attr):
if attr == "myattr":
#Setter for myattr
Be aware that __getattr__ and __getattribute__ are not the same. __getattr__ is only invoked when the attribute is not found.

Inherit and then override parent init

I have the following code:
# file1.py
class GenericScript(object):
def __init__(self):
self.start_time = time.time()
self.date_stem = str(timezone.now().date()).replace('-','')
self.script_name = os.path.basename(sys.argv[0]).replace('.py','')
self.file_name = None
self.log_file = None
self.integrity_field = '%s+%s' % (self.script_name, str(int(time.time())))
# file2.py
class RTUpdater(GenericScript):
def __init__(self):
self.integrity_field = '%s+%s' % (self.script_name, self.date_stem)
self.update_title_data = False
self.update_title_ranking = True
self.update_title_box_office = True
self.update_person_ranking = True
What I am trying to do is call RTUpdate() and get it to initialize all the items first in the parent Class and then add to those with its own __init__ method. However, when I call it, the self.integrity_field keep raising an error because self.script_name is not defined, meaning it's not first inheriting the parent __init__ variables. Here is how I'm calling it:
if __name__ == '__main__':
x = RTUpdater()
main(x)
>>> AttributeError: 'RTUpdater' object has no attribute 'script_name'
What am I doing wrong and how would I fix this?
You need to explicitly call the constructor of the parent class. Based on your inheritance of object I'm guessing you're using Python 2, so try this:
class RTUpdater(GenericScript):
def __init__(self):
super(RTUpdater, self).__init__()
# ...
If you are actually using Python 3 you can just use super().__init__().
You completly override __init__ as far as I see it. Just call super().__init__() in your inherited __init__ (so that the init of the parent will be run) and check if the error still persists.
Or if you are using Python 2 you need to fix the classes for the super call: super(RTUpdater, self).__init__().

making a function as an else inside an __init__

How to get a function inside if/else inside an __init__ :
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(self, response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", self.on_g)
because the program dont read the on_g() if i put an empty string!
If i use the on_g() outside in parallel with __init__() i need a declared variable, for example:
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
self.on_g()
def on_g(self):
print 'hello there'
will return hello there
Your bug is in
http_client.fetch("http://www.google.com/", self.on_g)
which should be
http_client.fetch("http://www.google.com/", on_g)
since you defined a function, not a method.
self (the instance you're creating through __init__ ) doesn't have a on_g method.
Functions for the class-es need to be defined at the class level (as shown on your second chunk of code). They are evaluated when the class is first... erm... "looked-up"? "evaluated"?
That's why your second piece of code works. How come you can call self.on_g within the __init__ when the actual definition of the on_g method seems to come later in the code? It's an odd behavior (at a first glance) for an interpreter, right? Well... That's because when you run self.on_g(), the whole Foo class has already been evaluated and on_g has been added to the class (not to the instance!: To the class)
class Foo(object):
def __init__(self, q, **keywords):
[ . . . ]
else:
self.on_g() # I can use self.on_g() eventhough is defined... _
# |
# |
def on_g(self): # <------------ LATER ---------------------------|
print 'hello there'
Whereas if you define your method within the __init__, the interpreter will yell at you:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.test()
a = Test()
Throws:
Traceback (most recent call last):
File "./test.py", line 10, in <module>
a = Test()
File "./test.py", line 8, in __init__
self.test()
AttributeError: 'Test' object has no attribute 'test'
Even if you think Oh, maybe the class doesn't have the test method because it's still within the __init__, and it will have it once the initialization is completed... Meeeck... Wrong:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
a = Test()
a.test()
Same AttributeError.
If you still want to add on_g to the class at runtime (very bad idea, IMHO) you can do the interpreter's job by doing this:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.__class__.test = test
self.test()
a = Test()
a.test()
... which correctly prints:
Hello
Hello
Now, the two most straightforward things to do I can think of are:
You move the def on_g(self) to the class level (as you showed in your second code snippet)
You call your http_client.fetch with on_g as a function local to the __init__'s scope (being picky with the language: on_g now is a function, not a method, since is not bound to an object anymore).
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", on_g)

Categories