Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.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 试图编程一个;至“U类”;总装饰师_Python_Decorator_Python Decorators - Fatal编程技术网

Python 试图编程一个;至“U类”;总装饰师

Python 试图编程一个;至“U类”;总装饰师,python,decorator,python-decorators,Python,Decorator,Python Decorators,假设我已经定义了: def to_class(cls): """ returns a decorator aimed to force the result to be of class cls. """ def decorating_func(func): def wrapper(*args, **kwargs): return cls(func(*args, **kwargs)) return wrapper return decorator(de

假设我已经定义了:

def to_class(cls):
  """ returns a decorator
  aimed to force the result to be of class cls. """
  def decorating_func(func):
    def wrapper(*args, **kwargs):
      return cls(func(*args, **kwargs))
    return wrapper
  return decorator(decorating_func)
我希望使用它来创建装饰器,将函数结果转换为给定类的对象。但是,这将不起作用:

class TestClass(object):
  def __init__(self, value):
    self._value = (value, value)

  def __str__(self):
    return str(self._value)

  @staticmethod
  @to_test_class
  def test_func(value):
    return value

to_test_class = to_class(TestClass)
as test_func将查找to_test_类,但找不到它。另一方面,在类定义之前将赋值放置到to_test_类也会失败,因为TestClass还没有定义

尝试将@to_class(TestClass)置于test_func的定义之上也会失败,因为方法是在类之前构造的(如果我没有错的话)

我发现的唯一解决方法是将to_test_类手动定义为装饰器,而不是从常规的“to_class”定义中返回

可能需要指出的是,这只是一个基本示例,但我希望在许多应用程序中使用to_类,例如在将返回值“插入”到类的构造函数之前修改它;我也希望将它用作其他类方法的装饰器

我确信有些人认为“to_class”装饰师是毫无意义的;相反,可以在修饰的方法中进行操作。尽管如此,我觉得它很方便,并且有助于提高可读性


最后,我想补充一点,这让我感兴趣20%是出于实际原因,80%是出于研究原因,因为我发现这是我对Python中的decorator的一般理解不够的。

问题是,decorator在定义它所修饰的东西时会得到评估,所以在定义方法
test_func()
时,调用了decorator
to_test_class
,即使它已经存在,它应该处理的东西(class
TestClass
)也不存在(因为这是在创建所有方法之后创建的)

也许您可以在使用类的位置使用占位符,然后(在创建类之后)在占位符位置填充该值(类)

例如:

lazyClasses = {}
def to_lazy_class(className):
  """ returns a decorator
  aimed to force the result to be of class cls. """
  def decorating_func(func):
    def wrapper(*args, **kwargs):
      return lazyClasses[className](func(*args, **kwargs))
    return wrapper
  return decorating_func 

class TestClass(object):
  def __init__(self, value):
    self._value = (value, value)

  def __str__(self):
    return str(self._value)

  @staticmethod
  @to_lazy_class('TestClass')
  def test_func(value):
    return value

lazyClasses['TestClass'] = TestClass

>>> TestClass.test_func('hallo')
<__main__.TestClass object at 0x7f76d8cba190>
lazyClasses={}
def to_lazy_类(类名):
“”返回一个装饰程序
旨在强制结果为cls类。”“”
def装饰功能(func):
def包装(*args,**kwargs):
返回lazyClasses[className](func(*args,**kwargs))
返回包装器
返回装饰函数
类TestClass(对象):
定义初始值(自身,值):
自我价值=(价值,价值)
定义(自我):
返回str(自身值)
@静力学方法
@to_lazy_类('TestClass'))
def测试函数(值):
返回值
懒散类['TestClass']=TestClass
>>>TestClass.test_func('hallo')

事实上,在类构造时,类对象本身尚未构造,因此您不能将其用作装饰器的基础

我能想到的一个解决方法是不要使用
staticmethod
decorator。相反,在您自己的decorator内部,重新使用
classmethod
decorator。通过这种方式,您可以确保Python至少为您传递关联类:

def to_class(func):
    """ returns a decorator
    aimed to force the result to be of class cls. """
    def wrapper(cls, *args, **kwargs):
        return cls(func(*args, **kwargs))
    return classmethod(wrapper)
然后像这样使用它:

class TestClass(object):
    def __init__(self, value):
        self._value = (value, value)

    def __str__(self):
        return str(self._value)

    @to_class
    def test_func(value):
        return value
演示:

>>> def to_class(func):
...     """ returns a decorator
...     aimed to force the result to be of class cls. """
...     def wrapper(cls, *args, **kwargs):
...         return cls(func(*args, **kwargs))
...     return classmethod(wrapper)
... 
>>> class TestClass(object):
...     def __init__(self, value):
...         self._value = (value, value)
...     def __str__(self):
...         return str(self._value)
...     @to_class
...     def test_func(value):
...         return value
... 
>>> TestClass.test_func('foo')
<__main__.TestClass object at 0x102a77210>
>>> print TestClass.test_func('foo')
('foo', 'foo')
>def to_类(func):
...     “”返回一个装饰程序
…旨在强制结果为cls类。”“”
...     def包装(cls、*args、**kwargs):
...         返回cls(func(*args,**kwargs))
...     返回类方法(包装器)
... 
>>>类TestClass(对象):
...     定义初始值(自身,值):
...         自我价值=(价值,价值)
...     定义(自我):
...         返回str(自身值)
...     @上课
...     def测试函数(值):
...         返回值
... 
>>>TestClass.test_func('foo')
>>>打印TestClass.test_func('foo'))
(‘foo’、‘foo’)
你的装饰器的通用版本并不容易;解决难题的唯一其他解决方法是使用元类黑客;请参见我在何处更详细地描述该方法

基本上,您需要进入正在构建的类名称空间,设置一个临时元类,然后依赖于至少存在一个类实例,然后装饰程序才能工作;临时元类方法与类创建机制挂钩,以便稍后检索构造的类


鉴于您正在使用此装饰器作为替代类工厂,这可能并不理想;如果有人使用您的修饰函数专门创建类实例,则元类将被调用得太迟。

好吧,您忘记了类是传递给用classmethod修饰的方法的第一个参数,因此您可以这样编写它:

def to_this_class(func):
    def wrapped(cls, value):
        res = func(cls, value)
        return cls(res)
    return wrapped

class TestClass(object):
    def __init__(self, value):
        self._value = (value, value)

    def __str__(self):
        return str(self._value)

    @classmethod
    @to_this_class
    def test_func(cls, value):
        return value

x = TestClass('a')

print x.test_func('b')

对于普通方法不起作用(它们不能被制作成类方法),但是当然也有类似的方法使用
。\uuuuu class\uuuu
。很好的解决方案@Alfe:“普通”方法已经是实例的一部分,因此不需要返回类的实例。我们讨论的是包装它们的返回值“普通”方法不一定返回它们所在类的实例。但我想你的措辞把我弄糊涂了。你的意思可能是“不需要向他们传递类”(这就是我在提到
\uu class\uuu
时的意思);由于这是一个董事会而不是PM会议,其他人可以稍后阅读,因此不仅仅是询问者的意图是相关的;还有其他人能从他的问题中理解什么,至少我对他的理解不同,所以你99.9%的可能性不是基于硬性数字(我的读者比例超过了0.1%);-)没错。我只是觉得他脑子里想的是一个普通的装饰师(甚至可能在课外的几个地方使用它),在这种情况下使用它遇到了麻烦。毕竟,强制结果为特定类的用例并不局限于静态方法。尽管需要添加“cls”。在希望使用不同的类的情况下是不可能的(毕竟,我们可能希望返回不同于c的类的实例)