I have a rather complex base class for some sqlalchemy models and I want to create a rails style setters but, since i’m fairly new to python, I’m stuck with a problem that I cant seem to bypass. I create the setters on the new method so I can have the triggered both on new instances and on queries but no matter what setter I define and execute it always picks the last setter to execute. An example serves better:
class Test(object):
columns = ['email', 'username']
def __new__( cls, *args, **kwargs ):
for column in cls.columns:
setattr( cls, "set%s" % column.capitalize(), lambda cls, v: cls.setAttribute( cls, column, v ) )
return super( Test, cls ).__new__( cls, *args, **kwargs )
@staticmethod
def setAttribute(cls, attribute, value):
print "Setting attribute %s with value %s" % ( attribute, value )
setattr( cls, attribute, value )
test = Test()
test.setEmail('test@test.com')
As you can see I’m setting the email but, when executed, the code tries to set the username which is the last column. Any idea why is that?
This happens because your
lambdafunction referencescolumnbut doesn’t pass it in as an argument:When this function is executed, it will look for the name
columnin a containing or global scope, and always find the value'username'because that is whatcolumnwas set to last.Here is a straightforward way to fix this using a default argument value:
Another alternative would be to use a closure (in a way, the mutable default argument is a type of closure):