Skip to content

Instantly share code, notes, and snippets.

@huyx
Created July 14, 2014 04:46
Show Gist options
  • Save huyx/543c822c1c64c2280383 to your computer and use it in GitHub Desktop.
Save huyx/543c822c1c64c2280383 to your computer and use it in GitHub Desktop.
支持字典、模块等的合并
# -*- coding: utf-8 -*-
u'''合并对象,特点:
- 字典对象并操作
- 其他对象替换
可以合并的对象包括:
- 字典
- 模块
- 其他符合条件的对象
'''
import inspect
from collections import OrderedDict
def isPublic(name):
return not name.startswith('_')
def isUpper(v):
return v.upper() == v
def isLower(v):
return v.lower() == v
def isMerableBaseType(o):
'''判断是否可合并
返回: True - 可合并 False - 不可合并 None - 不确定
'''
if isinstance(o, (basestring, tuple, list)):
return False
if isinstance(o, dict):
return True
if isinstance(o, OrderedDict):
return True
if inspect.ismodule(o):
return True
return None
def isSource(o):
result = isMerableBaseType(o)
if result is None:
return all((
hasattr(o, 'keys'),
hasattr(o, '__getitem__'),
))
return result
def isTarget(o):
result = isMerableBaseType(o)
if result is None:
return all((
hasattr(o, 'keys'),
hasattr(o, '__getitem__'),
hasattr(o, '__setitem__'),
))
return result
def isMergeable(target, source):
return isTarget(target) and isSource(source)
class Mergeable(object):
def __init__(self, o):
self.o = o
def keys(self):
return self.o.keys()
def __getitem__(self, key):
return self.o.__getitem__(key)
class MergeableModule(Mergeable):
def keys(self):
return [k for k in dir(self.o) if isPublic(k)]
def __getitem__(self, key):
return getattr(self.o, key)
class GeneralSource(Mergeable):
pass
class ModuleSource(MergeableModule):
pass
class GeneralTarget(Mergeable):
def __setitem__(self, key, value):
return self.o.__setitem__(key, value)
class ModuleTarget(MergeableModule):
def __setitem__(self, key, value):
setattr(self.o, key, value)
class CaseSensitiveBase(object):
'''大小写装饰类
'''
def __init__(self, mergeable):
self.mergeable = mergeable
def _match(self, key):
raise NotImplementedError
def keys(self):
return [k for k in self.mergeable.keys() if self._match(k)]
def __getitem__(self, key):
return self.mergeable.__getitem__(key)
def __setitem__(self, key, value):
return self.mergeable.__getitem__(key, value)
class UpperCase(CaseSensitiveBase):
def match(self, key):
return isUpper(key)
class LowerCase(CaseSensitiveBase):
def match(self, key):
return isLower(key)
def CaseSensitive(mergeable, case):
if isinstance(object, basestring):
case = case.lower()
if case == 'upper':
return UpperCase(mergeable)
elif case == 'lower':
return LowerCase(mergeable)
else:
return mergeable
def Source(source, case=None):
'''工厂函数,返回 Target 对象,所以采用首字母大写
'''
if inspect.ismodule(source):
return CaseSensitive(ModuleSource(source), case)
return CaseSensitive(GeneralSource(source), case)
def Target(target, case=None):
'''工厂函数,返回 Target 对象,所以采用首字母大写
'''
if inspect.ismodule(target):
return CaseSensitive(ModuleTarget(target), case)
return CaseSensitive(GeneralTarget(target), case)
def merge(target, source, case=None):
'''
>>> from collections import OrderedDict
>>> merge(OrderedDict(), OrderedDict([('a', 1)]))
OrderedDict([('a', 1)])
>>> merge(OrderedDict([('a', 1)]), OrderedDict([('a', 2)]))
OrderedDict([('a', 2)])
>>> merge(OrderedDict([('a', 1)]), OrderedDict([('b', 2)]))
OrderedDict([('a', 1), ('b', 2)])
>>> 'ismodule' in merge({}, inspect)
True
'''
target = Target(target)
source = Source(source)
targetKeys = target.keys()
sourceKeys = source.keys()
for key in sourceKeys:
sourceValue = source[key]
if key in targetKeys:
targetValue = target[key]
if isMergeable(targetValue, sourceValue):
merge(targetValue, sourceValue)
else:
target[key] = sourceValue
else:
target[key] = sourceValue
return target.o
if __name__ == '__main__':
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment