如何在装饰器中使用“@dataclass”装饰器?
How to use `@dataclass` decorator within a decorator?
我想创建一个 class 装饰器来预先定义一些属性和方法来装饰 class。同时,我想用 @dataclass
装饰器装饰这个装饰 class 。
为了让用户更轻松,我希望用户只需使用我的装饰器,以便 his/her class 被装饰成 @dataclass
.
所以这就是我想出的装饰 class,这样装饰后的 class 就有了新的属性 id_
。我提交这段代码是想知道decoartor的嵌套是不是'acceptable'?
基本上,我不太确定像函数一样调用装饰器(虽然它是一个函数),所以我想知道是否会有副作用?
from dataclasses import dataclass
# My library: complexitiy is allowed.
def indexer(orig_class):
orig_class = dataclass(orig_class)
# Copy of original __init__ to call it without recursion.
orig_init = orig_class.__init__
id_ = 10
def __init__(self,*args, **kws):
self.id_ = id_
orig_init(self, *args, **kws) # Call the original __init__
orig_class.__init__ = __init__ # Set the class' __init__ to the new one
return orig_class
# User environment: importing @indexer decorator: ease of use is targeted.
# Expected behavior is that @indexer provides same functions as @dataclass.
@indexer
class Truc:
mu : int
# Test
test = Truc(3)
test.mu
Out[37]: 3
test.id_
Out[38]: 10
顺便说一句,不知道装饰器是否比class继承更好,在添加属性和方法时?
谢谢指教!
最佳,
编辑
谁能读到这里,并且想知道装饰器和继承之间的使用。
在实施中走得更远,我最终坚持使用装饰器,因为在我看来,它提供了一种更灵活的方式来调整如果保留了继承的子项 class。
通过继承,我看不到父 class 如何对子属性有任何控制(例如使它们冻结),同时完全自由地 naming/defining 这些属性。
但这实际上是一个重要的属性我正在寻找数据class。
因此,可以使用以下 @indexer
装饰器查看当前状态。
它让用户可以自由地创建具有 he/she 想要的参数数量的 'data class',并将它们命名为 he/she 想要的。
但它使
成为可能
- 比较和检查装饰的 2 个实例之间的相等性 class。
- 实例一旦从 decorated class 创建,就无法修改(冻结)
- 它为装饰的 class 配备了一个(装饰时可修改的)属性
fields_sep
- 它为装饰器 class 配备了一种方法,用于打印在实例化装饰器 class 时定义的字符串参数值,而不是装饰器添加的那些值(如
fields_sep
)
它满足我的要求(我可以使用从 decorated class 创建的对象)作为字典或排序字典的键。
如果它能帮上忙,就在这里。
PS:如果您有任何建议或更好的做法,我欢迎他们。
from dataclasses import dataclass, asdict
# for optional arguments in decorator:
def indexer(index_class=None, *, fields_sep:str='.'):
def _tweak(index_class):
# Wrap with `@dataclass`.
index_class = dataclass(index_class, order= True, frozen=True)
# Copy of original __init__ to call it without recursion.
index_class_init = index_class.__init__
def __init__(self,*args, **kws):
object.__setattr__(self, "_fields_sep", fields_sep)
index_class_init(self, *args, **kws)
index_class.__init__ = __init__
def _to_str(self):
return self._fields_sep.join(map(str, asdict(self).values()))
index_class._to_str = property(_to_str)
return index_class
if index_class:
# Calling decorator without other parameters.
return _tweak(index_class)
# Calling decorator with other parameters.
return _tweak
# Test without parameter.
@indexer
class Test:
mu : int
nu : str
test = Test(3, 'oh')
assert test._to_str == '3.oh'
# Test with 'fields_sep' parameter.
@indexer(fields_sep='-')
class Test:
mu : int
nu : str
test = Test(3, 'oh')
assert test._to_str == '3-oh'
# Test (un)equality.
@indexer
class Test:
mu : int
nu : str
test1 = Test(3, 'oh')
test2 = Test(3, 'oh')
assert test1 == test2
test3 = Test(4, 'oh')
assert test1 != test3
# Test dict.
di = {test1:[1,2,3], test2:[7,8,9]}
assert len(di) == 1
assert di[Test(3, 'oh')] == [7,8,9]
Basically, I am not so sure about calling a decorator like a function
(while it is a function), so I wonder if there could be side effects?
装饰器在python
中是语法糖,PEP 318在动机给出了以下示例
def foo(cls):
pass
foo = synchronized(lock)(foo)
foo = classmethod(foo)
等同于
@classmethod
@synchronized(lock)
def foo(cls):
pass
换句话说,装饰器允许您编写更少的代码行来获得完全相同的结果。
我想创建一个 class 装饰器来预先定义一些属性和方法来装饰 class。同时,我想用 @dataclass
装饰器装饰这个装饰 class 。
为了让用户更轻松,我希望用户只需使用我的装饰器,以便 his/her class 被装饰成 @dataclass
.
所以这就是我想出的装饰 class,这样装饰后的 class 就有了新的属性 id_
。我提交这段代码是想知道decoartor的嵌套是不是'acceptable'?
基本上,我不太确定像函数一样调用装饰器(虽然它是一个函数),所以我想知道是否会有副作用?
from dataclasses import dataclass
# My library: complexitiy is allowed.
def indexer(orig_class):
orig_class = dataclass(orig_class)
# Copy of original __init__ to call it without recursion.
orig_init = orig_class.__init__
id_ = 10
def __init__(self,*args, **kws):
self.id_ = id_
orig_init(self, *args, **kws) # Call the original __init__
orig_class.__init__ = __init__ # Set the class' __init__ to the new one
return orig_class
# User environment: importing @indexer decorator: ease of use is targeted.
# Expected behavior is that @indexer provides same functions as @dataclass.
@indexer
class Truc:
mu : int
# Test
test = Truc(3)
test.mu
Out[37]: 3
test.id_
Out[38]: 10
顺便说一句,不知道装饰器是否比class继承更好,在添加属性和方法时? 谢谢指教! 最佳,
编辑
谁能读到这里,并且想知道装饰器和继承之间的使用。
在实施中走得更远,我最终坚持使用装饰器,因为在我看来,它提供了一种更灵活的方式来调整如果保留了继承的子项 class。
通过继承,我看不到父 class 如何对子属性有任何控制(例如使它们冻结),同时完全自由地 naming/defining 这些属性。
但这实际上是一个重要的属性我正在寻找数据class。
因此,可以使用以下 @indexer
装饰器查看当前状态。
它让用户可以自由地创建具有 he/she 想要的参数数量的 'data class',并将它们命名为 he/she 想要的。
但它使
- 比较和检查装饰的 2 个实例之间的相等性 class。
- 实例一旦从 decorated class 创建,就无法修改(冻结)
- 它为装饰的 class 配备了一个(装饰时可修改的)属性
fields_sep
- 它为装饰器 class 配备了一种方法,用于打印在实例化装饰器 class 时定义的字符串参数值,而不是装饰器添加的那些值(如
fields_sep
)
它满足我的要求(我可以使用从 decorated class 创建的对象)作为字典或排序字典的键。
如果它能帮上忙,就在这里。
PS:如果您有任何建议或更好的做法,我欢迎他们。
from dataclasses import dataclass, asdict
# for optional arguments in decorator:
def indexer(index_class=None, *, fields_sep:str='.'):
def _tweak(index_class):
# Wrap with `@dataclass`.
index_class = dataclass(index_class, order= True, frozen=True)
# Copy of original __init__ to call it without recursion.
index_class_init = index_class.__init__
def __init__(self,*args, **kws):
object.__setattr__(self, "_fields_sep", fields_sep)
index_class_init(self, *args, **kws)
index_class.__init__ = __init__
def _to_str(self):
return self._fields_sep.join(map(str, asdict(self).values()))
index_class._to_str = property(_to_str)
return index_class
if index_class:
# Calling decorator without other parameters.
return _tweak(index_class)
# Calling decorator with other parameters.
return _tweak
# Test without parameter.
@indexer
class Test:
mu : int
nu : str
test = Test(3, 'oh')
assert test._to_str == '3.oh'
# Test with 'fields_sep' parameter.
@indexer(fields_sep='-')
class Test:
mu : int
nu : str
test = Test(3, 'oh')
assert test._to_str == '3-oh'
# Test (un)equality.
@indexer
class Test:
mu : int
nu : str
test1 = Test(3, 'oh')
test2 = Test(3, 'oh')
assert test1 == test2
test3 = Test(4, 'oh')
assert test1 != test3
# Test dict.
di = {test1:[1,2,3], test2:[7,8,9]}
assert len(di) == 1
assert di[Test(3, 'oh')] == [7,8,9]
Basically, I am not so sure about calling a decorator like a function (while it is a function), so I wonder if there could be side effects?
装饰器在python
中是语法糖,PEP 318在动机给出了以下示例
def foo(cls):
pass
foo = synchronized(lock)(foo)
foo = classmethod(foo)
等同于
@classmethod
@synchronized(lock)
def foo(cls):
pass
换句话说,装饰器允许您编写更少的代码行来获得完全相同的结果。