Python 2.5.4. Fairly new to Python, brand new to decorators as of last night. If I have a class with multiple boolean attributes:
class Foo(object):
_bool1 = True
_bool2 = True
_bool3 = True
#et cetera
def __init__():
self._bool1 = True
self._bool2 = False
self._bool3 = True
#et cetera
Is there a way to use a single decorator to check that any setting of any of the boolean attributes must be a boolean, and to return the boolean value for any requested one of these variables?
In other words, as opposed to something like this for each attribute?
def bool1():
def get_boo1():
return self._bool1
def set_bool1(self,value):
if value <> True and value <> False:
print "bool1 not a boolean value. exiting"
exit()
self._bool1=value
return locals()
bool1 = property(**bool1())
#same thing for bool2, bool3, etc...
I have tried to write it as something like this:
def stuff(obj):
def boolx():
def fget(self):
return obj
def fset(self, value):
if value <> True and value <> False:
print "Non-bool value" #name of object???
exit()
obj = value
return locals()
return property(**boolx())
bool1 = stuff(_bool1)
bool2 = stuff(_bool2)
bool3 = stuff(_bool3)
which gives me:
File "C:/PQL/PythonCode_TestCode/Tutorials/Decorators.py", line 28, in stuff
return property(**boolx())
TypeError: 'obj' is an invalid keyword argument for this function
Any pointers on how to do this correctly?
Thanks,
Paul
You can try using a descriptor:
class BooleanDescriptor(object):
def __init__(self, attr):
self.attr = attr
def __get__(self, instance, owner):
return getattr(instance, self.attr)
def __set__(self, instance, value):
if value in (True, False):
return setattr(instance, self.attr, value)
else:
raise TypeError
class Foo(object):
_bar = False
bar = BooleanDescriptor('_bar')
EDIT:
As S.Lott mentioned, python favors Duck Typing over type checking.
Two important things.
First, "class-level" attributes are shared by all instances of the class. Like static
in Java. It's not clear from your question if you're really talking about class-level attributes.
Generally, most OO programming is done with instance variables, like this.
class Foo(object):
def __init__():
self._bool1 = True
self._bool2 = False
self._bool3 = True
#et cetera
Second point. We don't waste a lot of time validating the types of arguments.
If a mysterious "someone" provides wrong type data, our class will crash and that's pretty much the best possible outcome.
Fussing around with type and domain validation is a lot of work to make your class crash in a different place. Ultimately, the exception (TypeError
) is the same, so the extra checking turns out to have little practical value.
Indeed, extra domain checking can (and often does) backfire when someone creates an alternate implementation of bool
and your class rejects this perfectly valid class that has all the same features as built-in bool
.
Do not conflate human-input range checking with Python type checking. Human input (or stuff you read from files or URI's) must be range checked, but not not type checked. The piece of the application that does the reading of the external data defines the type. No need to check the type. There won't be any mysteries.
The "what if I use the wrong type and my program appears to work but didn't" scenario doesn't actually make any sense. First, find two types that have the same behavior right down the line but produce slightly different results. The only example is int
vs. float
, and the only time is really matters is around division, and that's taken care of by the two division operators.
If you "accidentally" use a string where a number was required, your program will die. Reliably. Consistently.