【问题标题】:What is the proper way to use @property in python在python中使用@property的正确方法是什么
【发布时间】:2017-11-08 15:58:40
【问题描述】:

我有以下代码,Dog 和 Cat 类是从 Animal 类继承的。 Person 类使用 Dog 和 Cat 类作为其实例。我想要返回实例名称的函数,如字符串“get the name 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

【问题讨论】:

  • 您是否在问是否有另一种方法可以获取不使用@property 的实例的name?我不太明白你的问题。
  • 不是真的,我想知道是否有另一种方法可以在不使用 @property 或不写的情况下从 john、john.dog、john.cat 获取实例名称同一属性两次
  • 它们不是同一个属性(即使实现看起来相同),因为它们作用于不相关的对象。也许你想要一个通用的基类,比如 NamedEntity(Animal 和 Person 都继承自),它定义了 name 属性。
  • 您可以为您的Animal 对象实现__str__ 以返回名称。然后你可以像这样使用它:print john.dog。但总的来说,你已经实施了什么是好的。可能你可以创建一个像Nameble 这样的类,或者任何你有名字+getter的构造函数的地方。你的对象应该从它延伸出来。
  • 我在下面为您提供了一个额外的基类或 Mixin 的示例(在此处使用基类,Mixin 有助于更复杂的结构)。不过,您的代码还不错。

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


【解决方案1】:

基于 cmets,我猜你想避免两次定义相同的方法。 您可以使用 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

二传手

在 cmets 中,您询问如果有人想写信给 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

我将 getter 和 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

【讨论】:

  • 为什么我不能使用super().__init__(name)?
  • 如果我有一个与 * namegetter * 完全一样的实例怎么办。这是否意味着发生了一些冲突?
  • super().__init__(name) 可以在 Python 3 中工作,但是您将问题标记为 Python 2.7 和 Python 3,所以我给了您 Python 2.7 示例。详情请见stackoverflow.com/a/576183/1331407。
  • 我不明白您所说的名为 namegetter 的实例究竟是什么意思。作为name 属性的值,完全可以。但是,您不能将其作为附加属性保存到Person。
  • 谢谢,我的意思是如果有人继承了 Animal 类,比如 class Cat(Animal): def __init__(self, food, n): super().__init__(name=n) self.food = food self.sound = '喵' self.namegetter = 'namegetter'
猜你喜欢
  • 2012-09-23
  • 2011-08-31
  • 2023-03-09
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多