Python:从方法中设置方法属性
我正在尝试制作一个python装饰器,它向类的方法添加属性,这样我就可以从方法本身中访问和修改这些属性。装饰代码是Python:从方法中设置方法属性,python,python-decorators,Python,Python Decorators,我正在尝试制作一个python装饰器,它向类的方法添加属性,这样我就可以从方法本身中访问和修改这些属性。装饰代码是 from types import MethodType class attribute(object): def __init__(self, **attributes): self.attributes = attributes def __call__(self, function): class override(obj
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
我在下面的玩具示例中尝试了这个装饰器
class bar(object):
@attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
虽然我可以从foo()中访问属性“a”的值,但无法将其设置为其他值事实上,当我调用bar().foo()
时,我会得到以下属性错误。
AttributeError: 'instancemethod' object has no attribute 'a'
为什么会这样?更重要的是,我如何才能实现我的目标
编辑 更具体地说,我试图找到一种简单的方法来实现位于类方法中的静态变量。继续上面的例子,我想实例化
b=bar()
,调用foo()
和doo()
方法,然后稍后访问b.foo.a
和b.doo.a
class bar(object):
@attribute(a=2)
def foo(self):
self.foo.a = 1
@attribute(a=4)
def doo(self):
self.foo.a = 3
虽然您可以通过将
self.foo.a=1
替换为self.foo.\uu dict\uuu['a']=1
来实现您的目标,但通常不建议这样做 虽然您可以通过将self.foo.a=1
替换为self.foo.\uu dict\uu['a']=1
来实现您的目标,但通常不建议这样做 如果您使用的是Python2-(而不是Python3)-每当您从实例检索方法时,都会创建一个新的实例方法
对象,它是类主体中定义的原始函数的包装
instance方法是函数的一个相当透明的代理-您可以通过它检索函数的属性,但不能设置它们-这就是为什么在self.foo.\uu dict\uu
中设置一个项是有效的
或者,您可以使用以下方法访问函数对象本身:
self.foo.im_func
-实例方法的im_func
属性指向基础函数。如果您使用的是Python2-(而不是Python3)-每当您从实例检索方法时,创建了一个新的实例方法
对象,它是类主体中定义的原始函数的包装器
instance方法是函数的一个相当透明的代理-您可以通过它检索函数的属性,但不能设置它们-这就是为什么在self.foo.\uu dict\uu
中设置一个项是有效的
或者,您可以使用以下方法访问函数对象本身:
self.foo.im_func
-实例方法的im_func
属性指向基础函数。最好的方法是根本不这样做
首先,不需要属性装饰器;您可以自己分配:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
但是,这仍然会遇到相同的错误。您需要执行以下操作:
self.foo.__dict__['a'] = 1
你可以改为使用元类…但这很快就会变得混乱
另一方面,还有更清洁的替代品
您可以使用默认值:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
<>当然,我的首选方法是完全避免使用一个可调用类(C++中的“函子”):
或者只使用经典类属性:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
如果您想从派生类中隐藏a
,请使用Python术语中所称的任何私有属性:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
编辑:您想要静态属性吗
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
编辑2:如果希望静态属性仅对当前函数可见,可以使用的“修改”函数:
它有点难看和粗俗。但它是有效的
我的建议是使用双下划线:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
虽然这对其他函数是可见的,但对其他任何函数都是不可见的(实际上,它在那里,但它被损坏了)
最终编辑:使用以下选项:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
@wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
做到这一点的最好方法是根本不做 首先,不需要属性装饰器;您可以自己分配:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
但是,这仍然会遇到相同的错误。您需要执行以下操作:
self.foo.__dict__['a'] = 1
你可以改为使用元类…但这很快就会变得混乱
另一方面,还有更清洁的替代品
您可以使用默认值:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
<>当然,我的首选方法是完全避免使用一个可调用类(C++中的“函子”):
或者只使用经典类属性:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
如果您想从派生类中隐藏a
,请使用Python术语中所称的任何私有属性:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
编辑:您想要静态属性吗
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
编辑2:如果希望静态属性仅对当前函数可见,可以使用的“修改”函数:
它有点难看和粗俗。但它是有效的
我的建议是使用双下划线:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
虽然这对其他函数是可见的,但对其他任何函数都是不可见的(实际上,它在那里,但它被损坏了)
最终编辑:使用以下选项:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
@wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
根据其他贡献者的回答,我提出了以下解决方法。首先,在类中包装一个词汇表,将不存在的属性解析为包装的词汇表,如下面的代码
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
此代码的学分为
然后使用将存储静态属性的statics
属性实现一个addstatic
装饰器
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
下面的代码是如何在方法上使用addstatic
decorator的示例
class bar(object):
@attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
然后,使用bar
类的实例产生:
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
使用这个statics术语的原因遵循jsbueno的回答,这表明我需要重载foo函数的点运算符和实例方法,我不确定这是否可行。当然,该方法的属性可以在self.foo.\uuu dict\uuuu中设置,但由于不推荐(正如brainovergrow所建议的那样),我提出了这个解决方法。我也不确定这是否会被推荐,我想应该由评论来决定。根据其他撰稿人的回答,我