2017-09-13 71 views
3

标题可能不是我想要做的最好的描述,但我不知道该怎么称呼它。我遇到了各种看起来相关的概念,名称分别是“装饰器”,“描述符”和“元类”,但我不知道我应该进一步调查哪些方法(如果有的话)。动态定义派生自类属性名称的方法?

考虑以下类:

class AnimalGreeter(object): 

    def __init__(self, greeting): 
     self.greeting = greeting 

    def greet(self, animal): 
     print(self.greeting + ", " + animal + "!") 

class MyGreeter(AnimalGreeter): 

    animals = ['dog', 'parrot'] 

我希望能够使用的MyGreeter一个实例是这样的:

greeter = MyGreeter("What's up") 
greeter.parrot 
# "What's up, parrot!" 

实际上,我想它充当如果我已定义MyGreeter而不是:

class MyGreeter(AnimalGreeter): 

    @property 
    def dog(self): 
     self.greet('dog') 

    @property 
    def parrot(self): 
     self.greet('parrot') 

In换句话说,我想动态定义从类(MyGreeter)的属性(animals)派生的名称的方法(dog()等)。

这样做的最好方法是什么?非常感谢!

+2

只实现'__getattr __(自我,动物)'。 – AChampion

+0

不能帮助,但我对你的用例感兴趣。你为什么需要这种行为? – FabienP

+1

@FabienP,在我的案例中'AnimalGreeter'是一个Django模型,'MyGreeter'是一个自定义混合,它可以处理具有可配置文件名的图像。我想要访问Django模板中的图像url,但Django的模板系统不允许将实例方法传递给参数。所以我不能在模板中做相当于'model.image_url('large')'。但是我可以访问模板中的实例属性,例如'model.large_image_url'。 – tino

回答

4

一个简单的方法来做到这一点也只是实现__getattr__(),例如:

class MyGreeter(AnimalGreeter): 
    animals = {'dog', 'parrot'} 

    def __getattr__(self, animal): 
     if animal in self.animals: 
      return self.greet(animal) 
     raise AttributeError("'{}' object unknown animal '{}'".format(type(self).__name__, animal)) 

>>> greeter = MyGreeter("What's up") 
>>> greeter.parrot 
What's up, parrot! 
>>> greeter.cat 
... 
AttributeError: 'MyGreeter' object unknown animal 'cat' 
+0

谢谢!这是我遇到的其中一个建议,但不确定我是否应该关注开销。 'AnimalGreeter'有很多其他属性可以经常访问。每次访问任何实例属性时都会执行此操作吗? – tino

+2

@tino否,只有在访问“不存在”的属性时才调用__getattr__',即在抛出AttributeError时调用该属性。 [阅读文档](https://docs.python.org/3/reference/datamodel.html#object.__getattr__) –

+0

@Rawing,啊,这很有道理。感谢您的链接和解释! – tino