装饰类失去对其属性的访问权限 [英] Decorated class looses acces to its attributes

查看:81
本文介绍了装饰类失去对其属性的访问权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现了一个装饰器,该装饰器就像一个吊饰一样工作,直到将属性添加到装饰的类中为止。当我实例化该类时,它无法访问calss属性。以下面的最小工作示例为例:

 从模块导入特殊功能

类numericMathFunctionDecorator:
def __init __(self,enableCache = True):
self.enableCache = enableCache

def __call __(self,wrapper):
def numericmathfunction(* args,** kwargs):
func = specialfunction(wrapper(* args,** kwargs))

使用装饰器参数(例如enableCache)对func进行一些设置

返回numericmathfunction

@NumericalMathFunctionDecorator(enableCache = True)
类包装器:
个位置= ['home','office']
configs = {
'home':
{
'attr1':'path / at / home',
'attr2':'jhdlt'
},
'office ':
{
'attr1':'path / at / office',
'attr2':'sfgqs'
}
}
def __init __(self,where ='home'):
#查找'Wrapper.configs [where]上的设置配置'。
断言Wrapper.places中的唯一有效位置是{}。format(Wrapper.places)
self .__ dict __。update(Wrapper.configs [where])

def __call __(self,X):
用X做东西并返回结果

返回X ** 2

model = Wrapper()

实例化Wrapper类(#1)时,出现以下错误:

  --------------------------- ------------------------------------------------ 
AttributeError追溯(最近一次呼叫最近)
< ipython-input-5-a99bd3d544a3>在< module>()
15中断言Wrapper.places中的仅有效位置是{}。format(Wrapper.places)
16
---> 17模型= Wrapper()

< ipython-input-5-a99bd3d544a3>在numericmathfunction(* args,** kwargs)
5 def __call __(self,wrapper):
6 def numericmathfunction(* args,** kwargs):
----> 7 func = wrapper(* args,** kwargs)
8返回数字数学函数
9

< ipython-input-5-a99bd3d544a3> in __init __(self,where)
13 def __init __(self,where ='home'):
14#在 Wrapper.configs [where]上查找设置配置。
---> 15断言Wrapper.places中的唯一有效位置是{}。format(Wrapper.places)
16
17模型= Wrapper()

AttributeError:'function '对象没有属性'places'

我想通过装饰器,包装器变成了一个松散的函数根据其属性...



关于如何解决此问题的任何想法?也许有解决方法

解决方案

您替换了 Wrapper (这是一个类)和 numericalmathfunction 函数对象。该对象没有任何类属性。



本质上,装饰器这样做:

  class包装器:
#...

包装器= numericMathFunctionDecorator(enableCache = True)(包装器)

因此,无论 NumericalMathFunctionDecorator .__ call __ 方法返回的内容是否已替换该类;现在,所有对 Wrapper 的引用都引用了该返回值。在 __ init __ 方法中使用名称 Wrapper 时,您引用的是全局变量,而不是原始类。 / p>

您仍然可以使用 type(self)访问当前类,或仅通过<$ c $引用这些属性c> self (其中名称查找属于该类):

  def __init __(self ,where ='home'):
#在 Wrapper.configs [where]上查找设置配置。
断言self.places中的仅有效位置是{}。format(self.places)
self .__ dict __。update(self.configs [where])

  def __init __( self,where ='home'):
#在'Wrapper.configs [where]'上查找设置配置。
cls = type(self)
断言在cls.places中,仅有效位置是{}。format(cls.places)
self .__ dict __。update(cls.configs [ ]]

在两种情况下,如果您这样做,最终都可以引用子类的属性子类包装器(在这种情况下您还是不能这样做,因为您必须将类从装饰器的闭包中退出)。



或者,您可以将原始类作为属性存储在返回的函数上:

  def __call __(self,wrapper ):
def numericmathfunction(* args,** kwargs):
func = specialfunction(wrapper(* args,** kwargs))

进行一些设置带有装饰器参数的函数(例如enableCache)

numericmathfunction .__ wrapped__ =包装器
返回numericmathfunction

然后在您的 __ init __ 中使用该引用:

  def __init __(self,where ='home'):
#在 Wrapper.configs [where]上查找设置配置。
cls =包装器
,而hasattr(cls,'__wrapped__'):
#删除任何装饰层,以获得原始的
cls = cls .__ wrapped__
断言在哪里在cls.places中,只有有效的位置是{}。format(cls.places)
self .__ dict __。update(cls.configs [where])


I implemented a decorator that worked like a charm until I added attributes to the decorated class. When I instantiate the class, it cannot acces the calss attributes. Take the following minimal working example :

from module import specialfunction

class NumericalMathFunctionDecorator:
    def __init__(self, enableCache=True):
        self.enableCache = enableCache

    def __call__(self, wrapper):
        def numericalmathfunction(*args, **kwargs):
            func = specialfunction(wrapper(*args, **kwargs))
            """
            Do some setup to func with decorator arguments (e.g. enableCache)
            """
        return numericalmathfunction

@NumericalMathFunctionDecorator(enableCache=True)
class Wrapper:
    places = ['home', 'office']
    configs = {
               'home':
                  {
                   'attr1': 'path/at/home',
                   'attr2': 'jhdlt'
                  },
               'office':
                  {
                   'attr1': 'path/at/office',
                   'attr2': 'sfgqs'
                  }
              }
    def __init__(self, where='home'):
        # Look for setup configuration on 'Wrapper.configs[where]'.
        assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
        self.__dict__.update(Wrapper.configs[where])

    def __call__(self, X):
        """Do stuff with X and return the result
        """
        return X ** 2

model = Wrapper()

When I instantiate the Wrapper class (#1), I get the following error :

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-a99bd3d544a3> in <module>()
     15         assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
     16 
---> 17 model = Wrapper()

<ipython-input-5-a99bd3d544a3> in numericalmathfunction(*args, **kwargs)
      5     def __call__(self, wrapper):
      6         def numericalmathfunction(*args, **kwargs):
----> 7             func = wrapper(*args, **kwargs)
      8         return numericalmathfunction
      9 

<ipython-input-5-a99bd3d544a3> in __init__(self, where)
     13     def __init__(self, where='home'):
     14         # Look for setup configuration on 'Wrapper.configs[where]'.
---> 15         assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
     16 
     17 model = Wrapper()

AttributeError: 'function' object has no attribute 'places'

I guess that with the decorator, Wrapper becomes a function that looses acces to its attributes...

Any ideas of how I can solve this ? Maybe there is a workaround

解决方案

You replaced Wrapper (which was a class) with the numericalmathfunction function object. That object doesn't have any of the class attributes, no.

In essence, the decorator does this:

class Wrapper:
    # ...

Wrapper = NumericalMathFunctionDecorator(enableCache=True)(Wrapper)

so whatever the NumericalMathFunctionDecorator.__call__ method returns has now replaced the class; all references to Wrapper now reference that return value. And when you use the name Wrapper in the __init__ method, you are referencing that global, not the original class.

You can still access the current class with type(self), or just reference those attributes via self (where the name lookup falls through to the class):

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    assert where in self.places, "Only valid places are {}".format(self.places)
    self.__dict__.update(self.configs[where])

or

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = type(self)
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])

In both cases you can end up with referencing an attribute on a subclass if you ever did subclass Wrapper (which you cannot do in this case anyway as you would have to fish the class out of the decorator closure).

Alternatively, you could store the original class as an attribute on the returned function:

def __call__(self, wrapper):
    def numericalmathfunction(*args, **kwargs):
        func = specialfunction(wrapper(*args, **kwargs))
        """
        Do some setup to func with decorator arguments (e.g. enableCache)
        """
    numericalmathfunction.__wrapped__ = wrapper
    return numericalmathfunction

then use that reference in your __init__:

def __init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = Wrapper
    while hasattr(cls, '__wrapped__'):
        # remove any decorator layers to get to the original
        cls = cls.__wrapped__
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])

这篇关于装饰类失去对其属性的访问权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆