在 python 中使用 @属性 的正确方法是什么

What is the proper way to use @property in python

我有以下代码,Dog 和 Cat class 继承自 Animal class。 Person class 正在使用 Dog 和 Cat class 作为其实例。我想要 return 实例名称的函数,例如 john 实例的字符串 "get the name xxx" 和 john 的 属性 狗,猫的名字。我尝试在 Animal class 和 Person 下编写 属性 namegetter 并且我可以得到我想要的。但是,是否有适当的方法来做到这一点?所以如果我有几个 class 之类的人,我不需要在 class

下写相同的 属性
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

根据评论,我猜您想避免两次定义相同的方法。 您可以使用 Mixins(在复杂的层次结构中)或只是另一个基础 class 来做到这一点。至于你是否可以避免写@property的问题:你可以不写,但是你必须在你的方法后面写大括号namegetter()

使用基数的示例 class:

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 定义中从它继承的方式:

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 这个名字听起来好像你需要它。下面,我为您定义了一个带有 getters 和 setters 的版本,允许您使用可选变量 {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

我将 getter 和 setter 分成两种方法,并将它们作为 namegetter 属性 提供。 Python 将根据您自动访问 属性 的方式 select 正确的方法。

然而,上述解决方案不再使用装饰器,这可能会降低代码的可读性。带有装饰器的版本是这个。请注意方法 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