What would be the most pythonic way to make an attribute that can be used in a lambda?
Use a closure to return a function to be used as a callback, and define each condition as a function (using lambda
or def
, your preference) instead of each setter as a function.
class Eggs(object): def __init__(self): self.spam = 'Monster' def spam_condition(string = None): return (string is not None) and (len(string) <= 32) self.spam_setter = self.set('spam', 'Ouch', spam_condition) spam_button.bind('<Enter>', self.spam_setter) self.spam_setter(val='Horse') def set(self, name, value, condition): def setter(val): if type(val) is not .... : # fill this in with the TYPE of the event value = val if condition(value): setattr(self, name, value) return setter
Edit: Now you can call the setter, which will check the condition, from anywhere.
Edit 2: This way, the setter will check if it got an event, and if not, use the value it's passed. You could also use:
if not isinstance(val, ....) : # fill this in with the CLASS of the event
I still suggest using a dict and calling it a day. Subclass it and override __setitem__
to do your data validation, then don't worry about getters:
#!/usr/bin/env pythonclass Egg(dict): def __init__(self, *args, **kwargs): super(Egg, self).__init__(*args, **kwargs) self['spam'] = 'foo' spam_button.bind('<Enter>', lambda: self.__setitem__('spam', 'Ouch')) def __setitem__(self, key, value): if key == 'spam': if len(value) > 32: raise ValueError('"%s" is longer than 32 characters') return super(Egg, self).__setitem__(key, value) raise KeyError(key)
The validation issue can be handled using a property
:
class Egg(object): @property def spam(self): return self._spam @spam.setter def spam(self, value): if len(value) <= 32: self._spam = value
Obviously, you can still use self._spam = 'spam '*10+'baked beans and spam'
with impunity.
Use the builtin setattr
:
lambda: setattr(self, 'spam', 'Ouch')
If you object to ..."spam"...
and prefer just ...spam...
, you can use methods of property
:
lambda: self.__class__.spam.fset(self, 'Ouch')
or, since property
is a descriptor:
lambda: type(self).spam.__set__(self, 'Ouch')
But the first version is preferred, I hope for obvious reasons.