加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Python – 我可以在不编写getter / setter的情况下包装属性赋值

发布时间:2020-12-20 13:41:33 所属栏目:Python 来源:网络整理
导读:这个问题的目标是确定我是否可以包装设置对象的属性,而不只是编写一个setter然后包装setter. 我正在尝试实现一个Observer模式,我不想编写超出我需要的代码(所以当然我会写一个很长的StackOverflow问题,哈哈 – 我认为长期收益是值得的). 我开始尝试用一个函
这个问题的目标是确定我是否可以包装设置对象的属性,而不只是编写一个setter然后包装setter.

我正在尝试实现一个Observer模式,我不想编写超出我需要的代码(所以当然我会写一个很长的StackOverflow问题,哈哈 – 我认为长期收益是值得的).

我开始尝试用一个函数包装obj .__ setattr__,但它没有按照我的预期做到,所以现在我想知道如果我不写一个,我是否可以包装赋值或改变一个对象的属性二传手.

这是我试过的:

class A(object):
    pass

def wrapper(obj,func):
    def inner(*args,**kwargs):
        print "called it"
        return func(*args,**kwargs)
    return inner

Stick = A()
Stick.__setattr__ = wrapper(Stick,Stick.__setattr__)
Stick.x = 14    #does not print "called it"

如果我只是写一个setter它会使一个简单的钩子,如:

class A(object):
    def __init__(self,x):
        self.x = x

    def set_x(self,new_x):
        self.x = x

但我希望能够以这样的方式实现Observer模式:每当obj.x因任何原因发生更改时,侦听器都会更新.如果obj.x是一个int,例如我可以直接设置它或使用obj.x = some_int来设置它,所以我想知道是否有一种方法来包装obj.x的任何/所有设置,例如,写obj.set_x(),obj.add_to_x(),obj.subtract_from_x(),obj.times_x()等.

编辑:感谢您指点我的属性,但我不知道它是如何帮助我以我迄今为止实施的方式包装它.

例如,如果我有一个这样的对象:

class Foo(object):
    def __init__(self,ex):
        self._x = ex
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self,value):
        self._x = value

…这很好,我看到我可以直接修改函数@ x.setter包装,但我希望创建一些我可以使用以下(虚构的伪代码)方式的东西:

A.x.setter = observing_function(A,A.x.setter)

…这样当A.x改变时,将调用observing_function并完成它将要做的事情.

如果它完全通知答案 – 我正在制作一个’记分牌’来显示视频游戏中的中心角色的得分和生命.而不是在每个循环期间不断检查或反复设置(我现在正在做的,这似乎是过度的),我只是希望它在角色的分数/生命发生变化时实际触发,而包装器似乎是最好的方法.

我希望避免这种情况:

def add_to_score(self,pts):
    self.score += pts
    scoreboard_object.text = self.score

…因为对我来说这很糟糕,即使它有效.此外,似乎很多代码只是为两个变量建立一个观察者模式:P

但这就是为什么我更愿意在事后包装二传手.我有两个不同的对象,不一定需要有关于彼此的硬编码数据;只是一个带有self.score属性的玩家对象和一个带有self.text属性的记分板对象,虽然在它们之间写“胶水”当然是必要的,但我希望写入set_score和set_text的方法不是至关重要的只是为了实现Observer模式.

如果最终我不能跳过写一个二传手(或者二传手),那么我想我会继续这样做;我只是希望避免它.

虽然现在这是一个非常具体的例子,但我也在一般意义上提出要求,因为能够仅仅观察变化的属性而不是围绕每个属性进行编码以准备观看某些属性似乎非常方便其他一些对象的变化. :/

解决方法

使用属性访问的特殊方法,描述符和所有其他方法仅适用于类.您无法在对象上覆盖它们.

使用事件(或pub / sub或我们现在称之为的任何系统)系统.让角色负责发出事件,但不是为了记住具体想要他们的人.

class ScoreChanged(Event):
    ...

class Character(ListenerMixin):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self,new):
        old = self._score
        self._score = new
        self.fire_event(ScoreChanged(self,old,new))

protag = Character()
scoreboard = Scoreboard()
scoreboard.listen_event(protag,ScoreChanged,scoreboard.on_score_change)

protag.score += 10

对象必然会在某处纠缠,但它变成了一个实现细节,而不是代码的主要部分.特别是,记分板不必是全局的,即使记分板不存在,角色仍然可以正常工作.

在this question上有一些实现和现有库的例子,但是如果你正在编写一个游戏,你可能已经在使用一个内置的库.我知道pyglet会这样做.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读