Dynamic methods and lambda functions

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Jan 23 08:08:04 EST 2009


On Fri, 23 Jan 2009 04:28:33 -0800, unineuro wrote:

> Hi,
> I want to add some properties dynamically to a class, and then add the
> corresponding getter methods. Something resulting in this:
> 
> class Person:
>     def Getname(self):
>         return self.__name
> 
>     def Getage(self):
>         return self.__age

(1) Properties don't work with classic classes. If you have setters to go 
with these getters, and you're using Python 2.x, your code will fail to 
work the way you think it should.

(2) Getters and setters are generally discouraged in Python unless you 
really need them. If all you are doing is getting/setting an attribute, 
then you're just wasting time. (Or if this is a learning exercise.)


> I've implemented the next code, creating the properties from a list:
> 
> props = [
>     ("name", "peter"),
>     ("age", 31),
>     ("wife", "mary")
>     ]
> 
> class Person:
>     def __init__(self):
>         for prop in props:
>             setattr(self, "__" + prop[0], prop[1]) 
>             setattr(Person, "Get" + prop[0], 
>             lambda self: getattr(self, "__" + prop[0]))

Seems awfully complicated. I'm not even sure it will work, due to 
Python's name-mangling. And let's not even talk about how broken it is to 
get your input to a class initializer from a global variable! What 
happens when you need a second instance?


> if __name__ == "__main__":
> 
>     person = Person()
> 
>     print person.__name
>     print person.__age
>     print person.__wife
>     print
>     print person.Getname()
>     print person.Getage()
>     print person.Getwife()
> 
> 
> And the resulting execution of this program is:
> 
> peter
> 31
> mary
> 
> mary
> mary
> mary
> 
> The attributes are right, but the getter are not working. The problem is
> that the lambda function always execute the last parameter passed for
> all instances of the methods. How could it be done the right way?


class Person(object):
    def __init__(self, name, age, wife):
        self.name = name
        self.age = age
        self.wife = wife

props = {"name": "peter", "age": 31, "wife": "mary"}

if __name__ == "__main__":
    person = Person(**props)
    print person.name
    print person.age
    print person.wife


If you really want getters, for whatever reason, then do it like this:

class Person(object):
    def __init__(self, name, age, wife):
        self._name = name
        self._age = age
        self._wife = wife


for prop in ('name', 'age', 'wife'):
    setattr(Person, prop, property( lambda self, prop=prop: 
    getattr(self, '_'+prop) ))



-- 
Steven



More information about the Python-list mailing list