Как определить свойства в __init__

Я хочу определить свойства в классе из функции-члена. Ниже приведен пример тестового кода, показывающего, как я хочу, чтобы это работало. Однако я не вижу ожидаемого поведения.

class Basket(object): def __init__(self): # add all the properties for p in self.PropNames(): setattr(self, p, property(lambda : p) ) def PropNames(self): # The names of all the properties return ['Apple', 'Pear'] # normal property Air = property(lambda s : "Air") if __name__ == "__main__": b = Basket() print b.Air # outputs: "Air" print b.Apple # outputs: <property object at 0x...> print b.Pear # outputs: <property object at 0x...> 

Как я могу заставить это работать?

3 Solutions collect form web for “Как определить свойства в __init__”

Вам нужно установить свойства в классе (то есть: self.__class__ ), а не на объект (т.е.: self ). Например:

 class Basket(object): def __init__(self): # add all the properties setattr(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" 

Для того, что это стоит, ваше использование p при создании lamdas в цикле не дает поведения, которого вы ожидаете. Поскольку значение p изменяется при прохождении цикла, два свойства, заданные в цикле, возвращают одно и то же значение: последнее значение p .

Это делает то, что вы хотели:

 class Basket(object): def __init__(self): # add all the properties def make_prop( name ): def getter( self ): return "I'm a " + name return property(getter) for p in self.PropNames(): setattr(Basket, p, make_prop(p) ) def PropNames(self): # The names of all the properties return ['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 

Другой способ сделать это – это метакласс … но они путают много людей ^^.

Потому что мне скучно:

 class WithProperties(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__', () ) ) def make_prop( name ): def getter( self ): return "I'm a " + name return property( getter ) for prop in props: attrs[ prop ] = make_prop( prop ) return super(WithProperties, cls).__new__(cls, name, bases, attrs) class Basket(object): __metaclass__ = WithProperties __props__ = ['Apple', 'Pear'] Air = property(lambda s : "I'm Air") class OtherBasket(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 

Почему вы определяете свойства на __init__ времени? Это сбивает с толку и умнее, поэтому у вас есть действительно хорошая причина. Проблема петли, которую указал Стеф, является лишь одним из примеров того, почему этого следует избегать.

Если вам нужно уточнить, какие свойства имеет подкласс, вы можете просто сделать del self.<property name> в подклассе __init__ method или определить новые свойства в подклассе.

Кроме того, некоторые стиль nitpicks:

  • Отступ в 4 пробела, а не 2
  • Не смешивайте типы котировок без необходимости
  • Используйте символы подчеркивания вместо верблюжьего случая для имен методов. PropNames -> prop_names
  • PropNames не обязательно должен быть методом
    Python - лучший язык программирования в мире.