Chi*_*ggs 8 python metaclass decorator
我想包装各种对象的每个方法,除了__init__使用装饰器.
class MyObject(object):
def method(self):
print "method called on %s" % str(self)
@property
def result(self):
return "Some derived property"
def my_decorator(func):
def _wrapped(*args, **kwargs):
print "Calling decorated function %s" % func
return func(*args, **kwargs)
return _wrapped
class WrappedObject(object):
def __init__(self, cls):
for attr, item in cls.__dict__.items():
if attr != '__init__' and (callable(item) or isinstance(item, property)):
setattr(cls, attr, my_decorator(item))
self._cls = cls
def __call__(self, *args, **kwargs):
return self._cls(*args, **kwargs)
inst = WrappedObject(MyObject)()
Run Code Online (Sandbox Code Playgroud)
但是,包装属性实例结果等同于:
@my_decorator
@property
def result(self):
return "Some derived property"
Run Code Online (Sandbox Code Playgroud)
当期望的结果与此相当时:
@property
@my_decorator
def result(self):
return "Some derived property"
Run Code Online (Sandbox Code Playgroud)
似乎属性对象的属性是只读的,以防止在属性包装后修改函数.我对已经要求的hackery水平不太满意,而且我还是不想深入研究属性对象.
我能看到的唯一其他解决方案是动态生成一个我希望避免的元类.我错过了一些明显的东西吗
此示例中还有其他一些问题,但是有一个疑问,您要做的就是包装属性时
包装属性时,请包装其__get__方法:
class MyObject(object):
def method(self):
print "method called on %s" % str(self)
@property
def result(self):
return "Some derived property"
def common(self, a=None):
print self
def my_decorator(func):
def _wrapped(*args, **kwargs):
print "Calling decorated function %s" % func
return func(*args, **kwargs)
return _wrapped
class WrappedObject(object):
def __init__(self, cls):
for attr, item in cls.__dict__.items():
if attr != '__init__' and callable(item):
setattr(cls, attr, my_decorator(item))
elif isinstance(item, property):
new_property = property(my_decorator(item.__get__), item.__set__, item.__delattr__)
setattr(cls, attr, new_property)
self._cls = cls
def __call__(self, *args, **kwargs):
return self._cls(*args, **kwargs)
inst = WrappedObject(MyObject)()
Run Code Online (Sandbox Code Playgroud)
那就是对完成这项工作的代码的简单修改。但是,为了避免重新编写其属性,我将其更改为包装的类的子类。您可以通过编程简单地创建一个带有名称的类型,带有基数的元组和以dict为参数的子类,从而以编程方式创建子类。
实际上,对给定类进行子类化几乎不需要对给定代码进行任何修改,但是对于type我指出的调用而言。我在这里进行了测试-将WrappedObject类更改为:
class WrappedObject(object):
def __init__(self, cls):
dct = cls.__dict__.copy()
for attr, item in dct.items():
if attr != '__init__' and callable(item):
dct[attr] = my_decorator(item)
elif isinstance(item, property):
new_property = property(my_decorator(item.__get__), item.__set__, item.__delattr__)
dct[attr] = new_property
self._cls = type("wrapped_" + cls.__name__, (cls,), dct)
def __call__(self, *args, **kwargs):
return self._cls(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4791 次 |
| 最近记录: |