【问题标题】:Dynamically defining methods with names derived from a class attribute?使用从类属性派生的名称动态定义方法?
【发布时间】:2017-09-13 15:49:31
【问题描述】:

标题可能不是对我正在尝试做的事情的最佳描述,但我不知道该怎么称呼它。我遇到了各种看似相关的概念,例如“装饰器”、“描述符”和“元类”,但我不知道我应该进一步研究这些方法中的哪一种(如果有的话)!

给定以下类:

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')

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

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

【问题讨论】:

  • 执行__getattr__(self, animal)即可。
  • 在这里帮不上忙,但我对您的用例很感兴趣。为什么需要这种行为?
  • @FabienP,在我的例子中,AnimalGreeter 是一个 Django 模型,MyGreeter 是一个自定义 mixin,用于处理具有可配置文件名的图像。我想访问 Django 模板中的图像 url,但 Django 的模板系统不允许将参数传递给实例方法。所以我不能在模板中做相当于model.image_url('large') 的操作。但我可以访问模板中的实例属性,例如model.large_image_url
  • @tino:很高兴知道,感谢您的解释!

标签: python metaprogramming


【解决方案1】:

一个简单的方法就是实现__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'

【讨论】:

  • 谢谢!这是我遇到的建议之一,但不确定我是否应该担心开销。 AnimalGreeter 有很多其他经常被访问的属性。每次我访问任何实例属性时都会执行此操作吗?
  • @tino 不,__getattr__ 仅在您访问“不存在”的属性时调用,即在抛出 AttributeError 时调用它。 Read the docs.
  • @Rawing,啊,这很有道理。感谢您的链接和解释!
猜你喜欢
  • 1970-01-01
  • 2014-02-19
  • 2013-05-01
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
相关资源
最近更新 更多