在python中使用@property的正确方法是什么?

时间:2017-11-08 15:58:40

标签: python python-2.7 python-3.x subclass

我有以下代码,Dog和Cat类继承自Animal类。 Person类使用Dog和Cat类作为其实例。我想有函数返回实例的名称,如字符串“获取名称xxx”为john实例和john的属性狗,猫的名字。我试图在Animal类和Person下修改属性 namegetter ,我可以得到我想要的东西。但是,如果有合适的方法可以做到这一点?所以,如果我有像Person这样的几个类,我不需要在类

下编写相同的属性
class Animal(object):
    def __init__(self, name):
        self.name = name

    @property
    def namegetter(self):
        return 'get the name of {}'.format(self.name)

class Cat(Animal):
    def __init__(self, food, name):
        super().__init__(name)
        self.food = food
        self.sound = 'meow'

class Dog(Animal):
    def __init__(self, food, name):
        super().__init__(name)
        self.food = food
        self.space = 'park'


class Person(object):

    def __init__(self, name):
        self.name = name
        self.dog = Dog("dog's food", "dog's name" )
        self.cat = Cat("dog's food", "cat's name")

    @property
    def namegetter(self):
        return 'get the name of {}'.format(self.name)

if __name__ == '__main__':
    john = Person('john')
    print(john.name) #john
    print(john.dog.name) #dog's name
    print(john.cat.name) #cat's name
    print(john.dog.namegetter) #get the name of dog
    print(john.cat.namegetter) #get the name of cat
    print(john.namegetter) #get the name of john

1 个答案:

答案 0 :(得分:1)

根据评论,我想你想避免两次定义相同的方法。 您可以使用Mixins(在复杂的层次结构中)或仅使用另一个基类来实现。关于你是否可以避免写@property的问题:你可以将其删除,但是你必须在你的方法namegetter()后面写括号。

使用基类的示例:

class NamedEntity(object):
    def __init__(self, name):
        self.name = name

    @property
    def namegetter(self):
        return 'get the name of {}'.format(self.name)


class Animal(NamedEntity):
    pass


class Cat(Animal):
    def __init__(self, food, name):
        super(Cat, self).__init__(name)
        self.food = food
        self.sound = 'meow'


class Dog(Animal):
    def __init__(self, food, name):
        super(Dog, self).__init__(name)
        self.food = food
        self.space = 'park'


class Person(NamedEntity):

    def __init__(self, name):
        super(Person, self).__init__(name)
        self.dog = Dog("dog's food", "dog's name" )
        self.cat = Cat("dog's food", "cat's name")


if __name__ == '__main__':
    john = Person('john')
    print(john.name) #john
    print(john.dog.name) #dog's name
    print(john.cat.name) #cat's name
    print(john.dog.namegetter) #get the name of dog
    print(john.cat.namegetter) #get the name of cat
    print(john.namegetter) #get the name of john

在一个更复杂的例子中,你可以改用Mixin,这基本上会改变你在类定义中继承它的方式:

class NamedEntityMixin(object):
    def __init__(self, name):
        self.name = name

    @property
    def namegetter(self):
        return 'get the name of {}'.format(self.name)


class Animal(NamedEntityMixin, object):
    # Imagine object being another parent class with additional properties and methods
    pass


class Cat(Animal):
    def __init__(self, food, name):
        super(Cat, self).__init__(name)
        self.food = food
        self.sound = 'meow'


class Dog(Animal):
    def __init__(self, food, name):
        super(Dog, self).__init__(name)
        self.food = food
        self.space = 'park'


class Person(NamedEntityMixin, object):
    # Imagine object being another parent class with additional properties and methods
    def __init__(self, name):
        super(Person, self).__init__(name)
        self.dog = Dog("dog's food", "dog's name" )
        self.cat = Cat("dog's food", "cat's name")


if __name__ == '__main__':
    john = Person('john')
    print(john.name) #john
    print(john.dog.name) #dog's name
    print(john.cat.name) #cat's name
    print(john.dog.namegetter) #get the name of dog
    print(john.cat.namegetter) #get the name of cat
    print(john.namegetter) #get the name of john

塞特斯

在评论中,您询问了有人想写信namegetter的内容。上面,我只定义了只读访问权限,因为名称namegetter对我来说就好像你需要它一样。下面,我为您定义了一个带有getter和setter的版本,允许您设置格式字符串,并根据需要替换可选变量{name}

class NamedEntity(object):
    def __init__(self, name):
        self.name = name
        self._namegetter = "get the name of {name}"

def _get_namegetter(self):
    return self._namegetter.format(name=self.name)

def _set_namegetter(self, namegetter):
    self._namegetter = namegetter

namegetter = property(_get_namegetter, _set_namegetter)


class Animal(NamedEntity):
    pass


class Cat(Animal):
    def __init__(self, food, name):
        super(Cat, self).__init__(name)
        self.food = food
        self.sound = 'meow'
        self.namegetter = 'catnamegetter'


class Dog(Animal):
    def __init__(self, food, name):
        super(Dog, self).__init__(name)
        self.food = food
        self.space = 'park'


class Person(NamedEntity):

    def __init__(self, name):
        super(Person, self).__init__(name)
        self.dog = Dog("dog's food", "dog's name" )
        self.cat = Cat("dog's food", "cat's name")


if __name__ == '__main__':
    john = Person('john')
    print(john.name) #john
    print(john.dog.name) #dog's name
    print(john.cat.name) #cat's name
    print(john.dog.namegetter) #get the name of dog
    print(john.cat.namegetter) #get the name of cat
    print(john.namegetter) #get the name of john

我分开了吸气剂和放大器将setter设置为两个方法,并使它们可用作namegetter属性。 Python将根据您自动访问属性的方式选择正确的方法。

然而,上述解决方案不再使用装饰器,这可能会使代码的可读性降低。这个有装饰器的版本。请注意,方法namegetter使用不同的装饰器定义了两次:

class NamedEntity(object):
    def __init__(self, name):
        self.name = name
        self._namegetter = "get the name of {name}"

    @property
    def namegetter(self):
        return self._namegetter.format(name=self.name)

    @namegetter.setter
    def namegetter(self, namegetter):
        self._namegetter = namegetter



class Animal(NamedEntity):
    pass


class Cat(Animal):
    def __init__(self, food, name):
        super(Cat, self).__init__(name)
        self.food = food
        self.sound = 'meow'
        self.namegetter = 'catnamegetter'


class Dog(Animal):
    def __init__(self, food, name):
        super(Dog, self).__init__(name)
        self.food = food
        self.space = 'park'


class Person(NamedEntity):

    def __init__(self, name):
        super(Person, self).__init__(name)
        self.dog = Dog("dog's food", "dog's name" )
        self.cat = Cat("dog's food", "cat's name")


if __name__ == '__main__':
    john = Person('john')
    print(john.name) #john
    print(john.dog.name) #dog's name
    print(john.cat.name) #cat's name
    print(john.dog.namegetter) #get the name of dog
    print(john.cat.namegetter) #get the name of cat
    print(john.namegetter) #get the name of john