Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中扩展@property.setter decorator_Python_Decorator_Python Decorators - Fatal编程技术网

在Python中扩展@property.setter decorator

在Python中扩展@property.setter decorator,python,decorator,python-decorators,Python,Decorator,Python Decorators,我正在编写多个类,将一个公共逻辑添加到一组属性中。这是代码的简化版本: 课程内容方面: _bar_prop=‘bar’ 定义初始值自身,条形值:int: 自。_bar=bar_值 @财产 def barself->int: 返回自我 @酒吧服务员 def barself,值:int->None: 自。_bar=值 执行动作本身、杆、道具、价值 perform_action总是有类似的形式,我想用一个decorator来封装它。基本上,我在寻找一种方法来写这样的东西: ... 定义@my_sett

我正在编写多个类,将一个公共逻辑添加到一组属性中。这是代码的简化版本:

课程内容方面: _bar_prop=‘bar’ 定义初始值自身,条形值:int: 自。_bar=bar_值 @财产 def barself->int: 返回自我 @酒吧服务员 def barself,值:int->None: 自。_bar=值 执行动作本身、杆、道具、价值 perform_action总是有类似的形式,我想用一个decorator来封装它。基本上,我在寻找一种方法来写这样的东西:

... 定义@my_setter 课程内容方面: ... @财产 def barself->int: 返回自我 @酒吧,我的酒吧 def barself,值:int->None: 自。_bar=值
是否可以扩展@property或@prop.setter来实现这一点?

多亏了@juanpa.arrivillaga,我想出了这个解决方案,实现了我自己的描述符:

myproperty.py 类别MyProperty: def _初始__self,fget=None,fset=None,key=None: self.fget=fget self.fset=fset self.key=key def u_get _self,obj,objtype=None: 如果obj为无: 回归自我 如果self.fget为无: raise AttributeErrorunreadable属性 return self.fgetobj 定义设置自身,对象,值: 如果self.fset为无: raise AttributeError无法设置属性 perfrom_actionself.key,value self.fsetobj,值 def getterself,fget: 返回类型selffget、self.fset、self.key def_setterself,fset: 返回类型self.fget、fset、self.key def setterself,键: 返回类型selfself.fget,self.fset,key=key.\u setter foo_aspect.py 从myproperty导入myproperty 课程内容方面: ... @我的财产 def barself->int: 返回自我 @bar.setterkey='bar' def barself,值:int->None: 自。_bar=值
感谢@juanpa.arrivillaga,我想出了这个解决方案,实现了我自己的描述符:

myproperty.py 类别MyProperty: def _初始__self,fget=None,fset=None,key=None: self.fget=fget self.fset=fset self.key=key def u_get _self,obj,objtype=None: 如果obj为无: 回归自我 如果self.fget为无: raise AttributeErrorunreadable属性 return self.fgetobj 定义设置自身,对象,值: 如果self.fset为无: raise AttributeError无法设置属性 perfrom_actionself.key,value self.fsetobj,值 def getterself,fget: 返回类型selffget、self.fset、self.key def_setterself,fset: 返回类型self.fget、fset、self.key def setterself,键: 返回类型selfself.fget,self.fset,key=key.\u setter foo_aspect.py 从myproperty导入myproperty 课程内容方面: ... @我的财产 def barself->int: 返回自我 @bar.setterkey='bar' def barself,值:int->None: 自。_bar=值
虽然复制和粘贴属性的参考代码并进行较小的修改将如您的答案所示,但为了代码重用,您可以将属性类划分为子类,并调用super来访问父类的方法

此外,实现中的setter函数不必要地实例化MyProperty的新实例,因为它可以通过返回self重用当前对象。\u setter:

以便:

class FooAspect:
    @MyProperty
    def bar(self) -> int:
        return self._bar

    @bar.setter(key='bar')
    def bar(self, value: int) -> None:
        self._bar = value

def perform_action(key, value):
    print(key, value)

f = FooAspect()
f.bar = 'foo'
产出:

bar foo

虽然复制和粘贴属性的参考代码并进行较小的修改将如您的答案所示,但为了代码重用,您可以将属性类划分为子类,并调用super来访问父类的方法

此外,实现中的setter函数不必要地实例化MyProperty的新实例,因为它可以通过返回self重用当前对象。\u setter:

以便:

class FooAspect:
    @MyProperty
    def bar(self) -> int:
        return self._bar

    @bar.setter(key='bar')
    def bar(self, value: int) -> None:
        self._bar = value

def perform_action(key, value):
    print(key, value)

f = FooAspect()
f.bar = 'foo'
产出:

bar foo

我的重点不是复制属性实现,这是非常通用的,如果getter和setter的逻辑总是相同的,那么可能不需要复制属性实现。因此,最好采取以下措施:

def perform_action(key, value):
    print(key, value)

class PerformKeyAction:
    def __init__(self, key):
        self.key = key

    def __get__(self, instance, owner):
        # maybe common getter behavior
        return getattr(instance, self.attr_name)

    def __set__(self, instance, value):
        perform_action(self.key, value)
        return setattr(instance, self.attr_name, value)

    def __set_name__(self, owner, name):
        self.attr_name = f'_{name}'

class FooAspect:
    bar = PerformAction(key='bar')

class BazAspect:
    buzz = PerformAction(key='buzz_key')

class FizzAspect:
    fang = PerformAction(key='fang_key')

这样,在编写各种类时就避免了样板文件,而不是在各种类中的各种getter/setter中重复样板文件。

我的目的不是复制属性实现,这是非常通用的,如果getter和setter的逻辑总是相同的,那么可能就不需要复制。因此,最好采取以下措施:

def perform_action(key, value):
    print(key, value)

class PerformKeyAction:
    def __init__(self, key):
        self.key = key

    def __get__(self, instance, owner):
        # maybe common getter behavior
        return getattr(instance, self.attr_name)

    def __set__(self, instance, value):
        perform_action(self.key, value)
        return setattr(instance, self.attr_name, value)

    def __set_name__(self, owner, name):
        self.attr_name = f'_{name}'

class FooAspect:
    bar = PerformAction(key='bar')

class BazAspect:
    buzz = PerformAction(key='buzz_key')

class FizzAspect:
    fang = PerformAction(key='fang_key')

这样,您在编写各种类时就避免了样板文件,而不是在各种类的各种getter/setter中重复样板文件。

您可能只需要编写自己的描述符,而不是试图扩展属性。整个要点或属性是为您提供一个非常常见的用例的实现,对于更复杂的事情,您应该只编写自己的描述符。@juanpa
谢谢你的建议,我没想过!我仍然希望扩展属性或实现我自己的版本,但我不确定它是通过哪种机制工作的,它不同于我以前使用的简单装饰器,因为它允许在代码中将与属性相关的所有内容保持在一起。这正是我所说的实现自己的描述符的意思。事实上,它是一个装潢师并不是真的相关。这不是它的基本工作原理,因为装饰器返回一个描述符对象。谢谢@juanpa.arrivillaga!这正是我需要的。我设法实现了我所需要的行为,并在下面发布了答案。@juanpa.arrivillaga OP要求的是在property类已经做的事情之上执行额外的功能,这正是类继承的目的。我已经包含了这样一个实现供参考。您可能只需要编写自己的描述符,而不是试图扩展属性。整个要点或属性是为您提供一个非常常见用例的实现,对于更复杂的事情,您只需编写自己的描述符。@juanpa.arrivillaga感谢您的建议,我没想过!我仍然希望扩展属性或实现我自己的版本,但我不确定它是通过哪种机制工作的,它不同于我以前使用的简单装饰器,因为它允许在代码中将与属性相关的所有内容保持在一起。这正是我所说的实现自己的描述符的意思。事实上,它是一个装潢师并不是真的相关。这不是它的基本工作原理,因为装饰器返回一个描述符对象。谢谢@juanpa.arrivillaga!这正是我需要的。我设法实现了我所需要的行为,并在下面发布了答案。@juanpa.arrivillaga OP要求的是在property类已经做的事情之上执行额外的功能,这正是类继承的目的。我包含了这样一个实现以供参考。实际上,在getter/setter中发生的事情是不可归纳的。为了简单起见,我使用了简单的隐藏字段访问,所以子类化属性更适合我的情况。实际上,在getter/setter中发生的事情是不可归纳的。为了简单起见,我使用了简单的隐藏字段访问,因此,子类化属性更适合我的情况。