I'm creating a Verdict class which will evaluate to true until it is set false after which it always evaluates false even if you set it to true. The only way I could think of to do that would be to have a property and a setter.
It works, but for simplicity rather than having:
v = Verdict()
v.verdict = ...
v.verdict = ...
v.verdict = ...
I thought I could do:
v = Verdict().verdict
v = ...
v = ...
v = ...
But it seems that v in the second case is the attribute directly, and is ignoring the setter.
class Verdict():
def __init__(self):
self.__verdict = True
#property
def verdict(self):
return self.__verdict
#verdict.setter
def verdict(self, value):
if self.__verdict is True:
self.__verdict = value
def __bool__(self):
return self.__verdict
class A():
v = Verdict().verdict
y = Verdict()
def foo(cls):
cls.y = False
cls.y = True # Uses setter and stays false
cls.v = False
cls.v = True # should use setter and stay false but doesn't
Is there a way to fix this, or a better method to achieve the Verdict?
You can't avoid using the v.verdict = ... syntax.
This is because properties require attribute access in order to work. Properties are descriptors, and the descriptor protocol only takes effect on attribute access.
If you store a property (or, more generally, a descriptor) in a variable, you've effectively robbed it of its functionality. Accessing a variable is just a name lookup, and assigning to a variable is just binding a value to a name. It's not possible to make an assignment like v = ... trigger your setter.
Related
I have a python class that has certain values. This class is just a wrapper class that is used as a datacontainer inside another class object.
When I have any variable in python, I can check if it is empty (or for that matter equal to False) by simply doing
my_variable = "something"
if my_variable
>>> True
my_variable = None # or False, or 0 or whatever equals False
if my_variable
>>> False
So far this is all as usual. But I'd like to behave my class exactly the same but only if a certain attribute has a certain value, otherwise it should return True. Is this possible or does python only check if my_variable is bound to something or not?
class Test(object):
def __init__(self, isTrue):
self.isTrue = isTrue
A = Test(True)
B = Test(False)
if A
>>> True
if B
>>> False
Sounds like you are looking for __bool__ (or __nonzero__ for Python 2).
class Test(object):
def __init__(self, isTrue):
self.isTrue = isTrue
def __bool__(self):
return self.isTrue
I want to do something decidedly unpythonic. I want to create a class that allows for forward declarations of its class attributes. (If you must know, I am trying to make some sweet syntax for parser combinators.)
This is the kind of thing I am trying to make:
a = 1
class MyClass(MyBaseClass):
b = a # Refers to something outside the class
c = d + b # Here's a forward declaration to 'd'
d = 1 # Declaration resolved
My current direction is to make a metaclass so that when d is not found I catch the NameError exception and return an instance of some dummy class I'll call ForwardDeclaration. I take some inspiration from AutoEnum, which uses metaclass magic to declare enum values with bare identifiers and no assignment.
Below is what I have so far. The missing piece is: how do I continue normal name resolution and catch the NameErrors:
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
def __getitem__(self, key):
try:
### WHAT DO I PUT HERE ??? ###
# How do I continue name resolution to see if the
# name already exists is the scope of the class
except NameError:
if key in self._forward_declarations:
return self._forward_declarations[key]
else:
new_forward_declaration = ForwardDeclaration()
self._forward_declarations[key] = new_forward_declaration
return new_forward_declaration
class MyMeta(type):
def __prepare__(mcs, name, bases):
return MetaDict()
class MyBaseClass(metaclass=MyMeta):
pass
class ForwardDeclaration:
# Minimal behavior
def __init__(self, value=0):
self.value = value
def __add__(self, other):
return ForwardDeclaration(self.value + other)
To start with:
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
...
But that won't allow you to retrieve the global variables outside the class body.
You can also use the __missin__ method which is reserved exactly for subclasses of dict:
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
# Just leave __getitem__ as it is on "dict"
def __missing__(self, key):
if key in self._forward_declarations:
return self._forward_declarations[key]
else:
new_forward_declaration = ForwardDeclaration()
self._forward_declarations[key] = new_forward_declaration
return new_forward_declaration
As you can see, that is not that "UnPythonic" - advanced Python stuff such as SymPy and SQLAlchemy have to resort to this kind of behavior to do their nice magic - just be sure to get it very well documented and tested.
Now, to allow for global (module) variables, you have a to get a little out of the way - and possibly somthing that may not be avaliablein all Python implementations - that is: introspecting the frame where the class body is to get its globals:
import sys
...
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
# Just leave __getitem__ as it is on "dict"
def __missing__(self, key):
class_body_globals = sys._getframe().f_back.f_globals
if key in class_body_globals:
return class_body_globals[key]
if key in self._forward_declarations:
return self._forward_declarations[key]
else:
new_forward_declaration = ForwardDeclaration()
self._forward_declarations[key] = new_forward_declaration
return new_forward_declaration
Now that you are here - your special dictionaries are good enough to avoid NameErrors, but your ForwardDeclaration objects are far from smart enough - when running:
a = 1
class MyClass(MyBaseClass):
b = a # Refers to something outside the class
c = d + b # Here's a forward declaration to 'd'
d = 1
What happens is that c becomes a ForwardDeclaration object, but summed to the instant value of d which is zero. On the next line, d is simply overwritten with the value 1 and is no longer a lazy object. So you might just as well declare c = 0 + b .
To overcome this, ForwardDeclaration has to be a class designed in a smartway, so that its values are always lazily evaluated, and it behaves as in the "reactive programing" approach: i.e.: updates to a value will cascade updates into all other values that depend on it. I think giving you a full implementation of a working "reactive" aware FOrwardDeclaration class falls off the scope of this question. - I have some toy code to do that on github at https://github.com/jsbueno/python-react , though.
Even with a proper "Reactive" ForwardDeclaration class, you have to fix your dictionary again so that the d = 1 class works:
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
def __setitem__(self, key, value):
if key in self._forward_declarations:
self._forward_declations[key] = value
# Trigger your reactive update here if your approach is not
# automatic
return None
return super().__setitem__(key, value)
def __missing__(self, key):
# as above
And finally, there is a way to avoid havign to implement a fully reactive aware class - you can resolve all pending FOrwardDependencies on the __new__ method of the metaclass - (so that your ForwardDeclaration objects are manually "frozen" at class creation time, and no further worries - )
Something along:
from functools import reduce
sentinel = object()
class ForwardDeclaration:
# Minimal behavior
def __init__(self, value=sentinel, dependencies=None):
self.dependencies = dependencies or []
self.value = value
def __add__(self, other):
if isinstance(other, ForwardDeclaration):
return ForwardDeclaration(dependencies=self.dependencies + [self])
return ForwardDeclaration(self.value + other)
class MyMeta(type):
def __new__(metacls, name, bases, attrs):
for key, value in list(attrs.items()):
if not isinstance(value, ForwardDeclaration): continue
if any(v.value is sentinel for v in value.dependencies): continue
attrs[key] = reduce(lambda a, b: a + b.value, value.dependencies, 0)
return super().__new__(metacls, name, bases, attrs)
def __prepare__(mcs, name, bases):
return MetaDict()
And, depending on your class hierarchy and what exactly you are doing, rememebr to also update one class' dict _forward_dependencies with the _forward_dependencies created on its ancestors.
AND if you need any operator other than +, as you will have noted, you will have to keep information on the operator itself - at this point, hou might as well jsut use sympy.
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