我有简单的装饰器,用于在尝试检索dict值时替换无效字符。
import types
class ContentInterface(dict):
def __getitem__(self, item):
raise NotImplementedError
class Content(ContentInterface):
def __getitem__(self, item):
return dict.__getitem__(self, item)
class DictDecorator(ContentInterface):
def __init__(self, interfaceContent, **config):
super(DictDecorator, self).__init__()
self._component = interfaceContent
self._config = config
def _replace(self, text):
return text
def _check(self, invalidCharacterSet, itemPath):
pass
def __getitem__(self, name):
item = self._component[name]
if isinstance(item, types.StringTypes):
newText = self._replace(item)
invalidCharacterSet = set([char for char in item if char not in newText])
self._check(invalidCharacterSet, name)
return newText
else:
return self.__class__(item, **self._config)
class ReplaceCommaDecorator(DictDecorator):
def _replace(self, text):
return text.replace(",", ' ')
class ReplaceDotDecorator(DictDecorator):
def _replace(self, text):
return text.replace('.', ' ')
class ReplaceColonDecorator(DictDecorator):
def _replace(self, text):
return text.replace(":", ' ')
class ReplaceSemicolonDecorator(DictDecorator):
def _replace(self, text):
return text.replace(";", ' ')
我想以下列方式使用它:
dictWithReplacedCharacters =\
ReplaceCommaDecorator( # Empty
ReplaceDotDecorator( # Empty
ReplaceColonDecorator( # Empty
ReplaceSemicolonDecorator( # Empty
Content({ # Data
'1':u'1A:B;C,D.E',
'2':{
'21':u'21A:B;C,D.E',
'22':u'22A:B;C,D.E',
}
}),
),
),
),
)
print dictWithReplacedCharacters['2']['21']
我有4个冗余的dict对象代表一个数据字典的装饰器。
我想强制上面的嵌套语句返回从继承自包含数据的Content的ReplaceSemicolonDecorator继承的ReplaceColonDecorator继承的ReplaceDotDecorator继承的ReplaceCommaDecorator对象。我想这可以在DictDecorator的__new__方法中解决。
答案 0 :(得分:0)
我不认为你所做的是正确的方法。我只想编写一个接受一组通用字符的类并正确地进行检查/替换,所以如果你想要转义更多的字符,你必须简单地传递一个包含所有字符的集合(加上可能有关如何替换的一些元信息)等)。
在您的示例中,代码不起作用,因为str.replace
需要两个参数,而您只传递一个。也许你想删除这个角色?在这种情况下,您应该replace(character, "")
。无论如何,如果您打算只用单个字符替换单个字符,那么您可以查看str.translate
模块中的maketrans
方法和string
函数。
否则可能是正则表达式(使用re.sub
)。
无论如何,你要求的方法就是:
class ContentInterface(dict):
pass
class Content(ContentInterface):
pass
class DictDecorator(ContentInterface):
def __new__(cls, other):
if isinstance(other, DictDecorator):
if not issubclass(cls, other.__class__) and not issubclass(other.__class__, cls):
new_cls = type('NewType', (cls, other.__class__), {})
return new_cls(other)
ob = dict.__new__(cls)
return ob
def __init__(self, interface, **config):
super(DictDecorator, self).__init__()
self._component = interface
self._config = config
# just to make the result appear with the content.
# You may not need this.
self.update(self._component)
def _replace(self, text):
return text
def _check(self, invalid_char_set, item_path):
pass
def __getitem__(self, name):
item = self._component[name]
if isinstance(item, basestring):
new_text = self._replace(item)
invalid_char_set = set(char for char in item if char not in new_text)
self._check(invalid_char_set, name)
return new_text
else:
# What you wrote here does not make sense...
# maybe you wanted: return self._config[name]?
return super(DictDecorator, self).__getitem__(name)
class ReplaceCommaDecorator(DictDecorator):
def _replace(self, text):
return text.replace(",", ' ')
class ReplaceDotDecorator(DictDecorator):
def _replace(self, text):
return text.replace('.', ' ')
class ReplaceColonDecorator(DictDecorator):
def _replace(self, text):
return text.replace(":", ' ')
class ReplaceSemicolonDecorator(DictDecorator):
def _replace(self, text):
return text.replace(";", ' ')
似乎有效:
>>> a = Content({'1': u'1A:B;C,D.E', '2': {'21': u'21A:B;C,D.E', '22': u'22A:B;C,D.E'}})
>>> r = ReplaceDotDecorator(ReplaceCommaDecorator(a))
>>> r['1']
u'1A:B;C D E'
>>> r = ReplaceColonDecorator(ReplaceDotDecorator(ReplaceCommaDecorator(a)))
>>> r['1']
u'1A B;C D E'
可能有更好的方法可以做到这一点,也许使用元类,但这是我能想到的唯一方法。
编辑:
顺便说一下,如果您不确切知道自己在做什么,我认为继承内置类型并不是一个好主意:
>>> class MyDict(dict): pass
...
>>> a = MyDict(a=1, b=2)
>>> a
{'a': 1, 'b': 2}
>>> a.__class__
<class '__main__.MyDict'>
>>> copy = a.copy()
>>> copy.__class__ # Wrong class.
<type 'dict'>
或另一个例子:
>>> class MyDict(dict):
... def __getitem__(self, key):
... if key.startswith('a'):
... return 'BAD!'
... return super(MyDict, self).__getitem__(key)
...
>>> my = MyDict(a=1, b=2)
>>> my['a']
'BAD!'
>>> my['b']
2
>>> my.keys()
['a', 'b']
>>> my.values() #you'd expect ['BAD!', 2]
[1, 2]
因此,请务必重新实现您将要使用的每种方法,这可能会导致类似的事情。