程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

有没有比使用装饰器更好的方法来检测属性何时改变?

发布于2024-11-25 16:41     阅读(720)     评论(0)     点赞(7)     收藏(4)


我一直在重构一个用于将文本传送到屏幕上的文本类。我最近了解了@property装饰器,并认为在这个类中使用它会有所帮助。
这是我正在编写的代码的精简版本:

class Text:
    def __init__(self, text, antialias):
        self.text = text
        self.antialias = antialias
        self._render_text()

    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, value):
        self._text = value
        self._requires_render = True

    @property
    def antialias(self):
        return self._antialias

    @antialias.setter
    def antialias(self, value):
        self._antialias = value
        self._requires_render = True

    def _render_text(self):
        self._required_render = False

    def blit(self):
        if self._requires_render:
            self._render_text()
        # blit text to screen

我注意到我使用 setter 和 getter 的主要动机是更改一个属性,该属性在将文本传送到屏幕之前命令重新渲染文本。这确保了更改文本对象的属性在事件循环中正确更新。它还确保如果连续调用多个需要重新渲染文本的属性,则只会触发一次重新渲染,因为重新渲染检查在每个游戏循环中只发生一次。
然而,这似乎也有些过度,我想知道是否有办法编写一个@property包含该self._requires_render行的自定义对象。虽然经过一番搜索,没有发现任何人遇到同样的问题,但我还是认为我的逻辑可能有缺陷,并且有一种更简单的方法来检测对象的属性何时更新,并运行一些代码。


解决方案


是的 - 理想的情况是使用与其property自身相同的机制 - 但财产并不是理想的。

Python 中的和常规方法都property使用所谓的descriptor协议——这意味着类中关联的属性可以具有__get____set__方法,它们用于在使用符号访问值时.

基本上,您所需要的只是一个__set__设置_requires_render属性的方法,否则将允许透明地访问该属性。您可以利用__set_name__与描述符协议相关联的方法,该方法在类创建时由语言调用:

class RenderNeeded:
    def __set_name__(self, owner, name):
        self.name = name
    def __get__(self, instance, owner):
        if instance is None:
             return self
        return instance.__dict__[self.name]
    def __set__(self, instance, value):
        instance._requires_render = True
        instance.__dict__[self.name] = value



from functools import wraps


# and for methods instead of variables,
# this is the decorator approach:

def clear_rendering(func):
    @wraps(func)
    def wrapper(self, *args, **kw):
        result = func(self, *args, **kw)
        self._requires_render = False
        return result
    return wrapper
   
class Text:
    def __init__(...):
        ...
    text = RenderNeeded()
    antialias = RenderNeeded()
    
    @clear_rendering
    def blit(self, ...):
        # blit text code ...
        ...

除了创建自定义描述符之外的另一种方法是__setattr__直接在类中自定义方法:

class Text:
    def __init__(self, text, antialias):
         ...
    def __setattr__(self, attr, value):
         if attr in {"text", "antialias", ...}:
               # this triggers a recursive call, but there is no problem. Just use `super().__setattr__` to avoid it, if preferred:
               self._requires_render = True
          return super().__setattr__(attr, value)


所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:https://www.pythonheidong.com/blog/article/2045893/ad1e7b0456e96ace7aee/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

7 0
收藏该文
已收藏

评论内容:(最多支持255个字符)