Más específicamente, quiero ser compatible con lambda: <some_or_other_setter>
, pero quiero mantener el código claro y conciso. Debo validar el valor, entonces necesito un setter de algún tipo. Necesito usar lambda porque necesito pasar devoluciones de llamada a los eventos de Tkinter. También necesito poder modificar el valor del atributo fuera de un enlace.¿Cuál sería la forma más pitónica de crear un atributo que se pueda usar en una lambda?
En mis ejemplos siguientes, suponga que un widget de botón llamado spam_button
ha sido declarado globalmente. Supongamos también que la clase Eggs
tendrá al menos 10 atributos de los que se necesita acceder a todos de la misma manera (me gusta la coherencia).
La primera manera es posible que pudiera hacer esto es usar sólo captadores y definidores:
class Eggs(object):
def __init__(self):
self._spam = ''
self.set_spam('Monster')
print self.get_spam()
spam_button.bind('<Enter>', lambda: self.set_spam('Ouch'))
def set_spam(self, spam):
if len(spam) <= 32:
self._spam = spam
def get_spam(self):
return self._spam
Pero si puedo usar este método y tener un montón de atributos, el código puede ser demasiado larga para administrar.
La segunda manera de que pudiera hacer esto es propiedades de uso, y el uso de la incubadora en la devolución de llamada:
class Eggs(object):
def __init__(self):
self._spam = ''
self.spam = 'Monster'
print self.spam
spam_button.bind('<Enter>', lambda: self.set_spam('Ouch'))
def set_spam(self, spam):
if len(spam) <= 32:
self._spam = spam
def get_spam(self):
return self._spam
spam = property(get_spam, set_spam)
De esta manera es un poco más sencillo que el primero cuando se accede al atributo directamente, pero es inconsistente cuando se usa lambda.
La tercera manera de hacer esto sería hacer una clase adicional con métodos get y set:
class Spam(object):
def __init__(self):
self._value = ''
def set(self, value):
if len(spam) <= 32:
self._value = value
def get(self):
return self._value
class Eggs(object):
def __init__(self):
self._spam = ''
self.spam = Spam()
self.spam.set('Monster')
print self.spam.get()
spam_button.bind('<Enter>', lambda: self.spam.set('Ouch'))
Este método es más organizado que el primero, pero tendrá que hacer una clase para cada tipo de validación
La última forma que podría hacer es utilizar métodos en lugar de propiedades (propiedades fueron el segundo ejemplo):
class Eggs(object):
def __init__(self):
self._spam = ''
self.spam('Monster')
print self.spam()
spam_button.bind('<Enter>', lambda: self.spam('Ouch'))
def spam(self, spam=None):
if spam != None:
if len(spam) <= 32:
self._spam = spam
else:
return self._spam
Este método probablemente será la más corta, pero es más difícil de un vistazo para saber si Estoy consiguiendo o poniendo.
¿Cuáles (si alguno) de estos métodos son preferidos?
Gracias por la idea, pero realmente no quiero usar cadenas para acceder a los atributos (también puedo usar un diccionario), y esto no proporciona una manera de establecer y validar el valor fuera de un enlace (a menos que haga 'self.set ('spam', 'Ouch', spam_condition)()' cada vez que quiera establecer el valor, que es realmente feo). Además, deseará agregar un parámetro 'event' a la función' setter', o bien Tkinter no puede pasar el evento (y obtiene un 'ValueError'). –
Ahora el setter se puede usar desde cualquier lugar. – agf
Si utilizo 'lambda e: self.spam_setter()' como devolución de llamada y elimino el parámetro 'event' de' setter', no necesito especificar 'val =' cada vez que establezco el valor. ¿Es posible deshacerse de la 'e' de' lambda e: 'en la devolución de llamada? –