Skip to content Skip to sidebar Skip to footer

How To Define Properties In __init__

I whish to define properties in a class from a member function. Below is some test code showing how I would like this to work. However I don't get the expected behaviour. class Bas

Solution 1:

You need to set the properties on the class (ie: self.__class__), not on the object (ie: self). For example:

classBasket(object):

  def__init__(self):
    # add all the propertiessetattr(self.__class__, 'Apple', property(lambda s : 'Apple') )
    setattr(self.__class__, 'Pear', property(lambda s : 'Pear') )

  # normal property
  Air = property(lambda s : "Air")

if __name__ == "__main__":
  b = Basket()
  print b.Air # outputs: "Air"print b.Apple # outputs: "Apple"print b.Pear # outputs: "Pear"

For what it's worth, your usage of p when creating lamdas in the loop, doesn't give the behavior that you would expect. Since the value of p is changed while going through the loop, the two properties set in the loop both return the same value: the last value of p.

Solution 2:

This does what you wanted:

classBasket(object):
  def__init__(self):
    # add all the propertiesdefmake_prop( name ):
        defgetter( self ):
            return"I'm a " + name
        returnproperty(getter)

    for p in self.PropNames():
        setattr(Basket, p, make_prop(p) )

  defPropNames(self):
    # The names of all the propertiesreturn ['Apple', 'Pear', 'Bread']

  # normal property
  Air = property(lambda s : "I'm Air")

if __name__ == "__main__":
  b = Basket()
  print b.Air 
  print b.Apple 
  print b.Pear 

Another way to do it would be a metaclass ... but they confuse a lot of people ^^.

Because I'm bored:

classWithProperties(type):
    """ Converts `__props__` names to actual properties """def__new__(cls, name, bases, attrs):
        props = set( attrs.get('__props__', () ) )
        for base in bases:
            props |= set( getattr( base, '__props__', () ) )

        defmake_prop( name ):
            defgetter( self ):
                return"I'm a " + name
            returnproperty( getter )

        for prop in props:
            attrs[ prop ] = make_prop( prop )

        returnsuper(WithProperties, cls).__new__(cls, name, bases, attrs)       

classBasket(object):
    __metaclass__ = WithProperties
    __props__ = ['Apple', 'Pear']

    Air = property(lambda s : "I'm Air")

classOtherBasket(Basket):
    __props__ = ['Fish', 'Bread']

if __name__ == "__main__":
    b = Basket()
    print b.Air 
    print b.Apple 
    print b.Pear 

    c = OtherBasket()
    print c.Air 
    print c.Apple 
    print c.Pear
    print c.Fish 
    print c.Bread 

Solution 3:

Why are you defining properties at __init__ time? It's confusing and clever, so you better have a really good reason. The loop problem that Stef pointed out is just one example of why this should be avoided.

If you need to redifine which properties a subclass has, you can just do del self.<property name> in the subclass __init__ method, or define new properties in the subclass.

Also, some style nitpicks:

  • Indent to 4 spaces, not 2
  • Don't mix quote types unnecessarily
  • Use underscores instead of camel case for method names. PropNames -> prop_names
  • PropNames doesn't really need to be a method

Post a Comment for "How To Define Properties In __init__"