Python 如何在设置/检索属性时自动转义属性?
我正在寻找一种在设置某些属性时执行一些自定义转义的方法,以及在从我的一个对象检索这些属性时执行相应的取消转义代码的方法。我已经看过了uuuu setattr uuuuuuuuuuu getattr uuuuuuuuuuuu和uuuuuuu getattribute uuuuuuuuuuu,但看不到它们与属性的关系 例如,我有一个类,例如:Python 如何在设置/检索属性时自动转义属性?,python,Python,我正在寻找一种在设置某些属性时执行一些自定义转义的方法,以及在从我的一个对象检索这些属性时执行相应的取消转义代码的方法。我已经看过了uuuu setattr uuuuuuuuuuu getattr uuuuuuuuuuuu和uuuuuuu getattribute uuuuuuuuuuu,但看不到它们与属性的关系 例如,我有一个类,例如: class Bundle(object): def __init__(self): self.storage = Storage()
class Bundle(object):
def __init__(self):
self.storage = Storage()
@property
def users_name(self):
"""
Get the user's name
"""
return self.storage.users_name
@users_name.setter
def users_name(self, users_name):
"""
Set the user's name
"""
# only permit letters and spaces.
if not re.match('^[A-Za-z ]+$', users_name):
msg = "'%s' is not a valid users_name. It must only contain letters and spaces" % users_name
log.fatal(msg)
raise ConfigurationError(msg)
self.storage.users_name = users_name
...
对象上有几个这样的属性
我想要的是一个方法,它只会影响我的一些属性(如users_name,但不影响“storage”),并在设置/检索时转义/取消转义该值
replace('%','%')
。同样,我希望有一种方法,每次检索属性时都会在返回它之前对值运行replace('%','%')
另外,由于“Bundle”中的大多数属性只是代理到后端存储,如果有一种方法可以说“如果属性在这个列表中,只需调用self.storage.property_NAME=VALUE
”,那就好了。有时候,尽管我希望能够覆盖该赋值,例如对要设置的值运行正则表达式
所以,实际上,我在寻找一种方式来表示“当设置属性时,始终调用此方法。然后,如果存在具体的@property.setter,则调用它,而不是执行self.storage.key=value
”
(doh!我的意思是uuu getattr uuuuuuuuu&uuuuu setattr uuuuuuuuuuuuuu不是uuuuuuu get uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu阅读谷歌叔叔在这方面的建议,到试验结束时,所有错误都变得非常清楚。在您的情况下,您可能不需要
\uuu getatribute\uuuuuuuuuuuuuuuuuu
,因为它是在访问时调用的,而不是查看obect的\uuuuuuuuu dict
我不习惯使用装饰器,因为使用property()
内置对我来说更清楚:
方法
\uuuu set\uuuu()
和\uuu get\uuuu()
用于描述符类,这意味着您需要为属性定义类。很好的示例:
实际上,您可能要查找的是通过覆盖类中的
\uuuuSetAttr\uuuuuuuuu()
和\uuuuuuuuuGetAttr()\uuuuuuuuuuu
方法(如果从2.7.x中的对象
派生,则可用)来访问的属性:
属性装饰器按照协议创建一个对象,
\uuuuuu get\uuuuuu
,\uuuu set\uuuuuu
方法在该协议下活动
我能想到的向某些属性添加其他行为的最佳方法是创建
您自己的装饰器。此装饰器将遵循相同的协议,包装最初由Python创建的属性,并添加所需的转义/取消转义行为。这将允许您将“特殊”转义属性标记为:
@escaped
@property
def users_name(self):
...
只有这些属性才会得到特殊处理。下面是一个如何实现这一点的快速示例:
class escaped:
def __init__(self, property_to_wrap):
# we wrap the property object created by the other decorator
self.property = property_to_wrap
def __get__(self, instance, objtype=None):
# delegate to the original property
original_value = self.property_to_wrap.__get__(instance, objtype)
# ... change the data however you like
return frotz(original_value)
def __set__(self, instance, new_value):
actual_value = frob(new_value)
self.property.__set__(instance, actual_value)
...
对于所有描述符方法都应该重复相同的操作。您还必须将属性本身的getter
,setter
,deleter
方法委托给属性本身(以允许您在包装属性中使用@users\u name.setter
等语法。您可以查看以获取帮助
这里也可以找到一些细节:。我使用装饰师提供了一个不同的答案,但是如果你真的喜欢使用神奇的方法,有一种方法:
class Magic(object):
@staticmethod
def should_be_escaped(property_name):
return not "__" in property_name
def __getattribute__(self, property):
value = object.__getattribute__(self, property)
if Magic.should_be_escaped(property):
value = value.replace("%%", "%")
return value
def __setattr__(self, property, value):
if Magic.should_be_escaped(property):
value = value.replace("%", "%%")
object.__setattr__(self, property, value)
调用object.\uuuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu和object.\uuuuuuuuu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
这是一个更糟糕的解决方案,原因在于是否应该转义
,您必须根据名称决定是否应该转义属性。这很难正确执行,而且您必须关心特殊名称、存储
变量等
例如,上面的should\u escape
的实现非常不完整,它将尝试在对象的方法上调用replace
,因此应该为属性类型添加一个检查。有很多这样的情况。这就是为什么我建议将decorator解决方案作为cleaner-它显式地标记谁收到了这种特殊的行为,并且没有令人不快的意外后果。你几乎永远不想使用\uuuu getattribute\uuuu
。相反,使用\uu getattr\uuuuuu
。区别在于总是调用\uu getattr\uuuuuu
,而\uu getattr\uuuuuuuuu>只为缺少属性而调用