Я решил, что это интересная проблема. Прежде всего, этот класс собирает имена элементов или атрибутов, когда вы пытаетесь получить элементы или атрибуты из него. Затем он может использовать эти собранные операции, чтобы получить или установить соответствующее значение в иерархии объектов. Он также имеет несколько удобных методов для создания функции set_to_x
, как в вашем примере.
Класс:
class LocationProxy(object):
def __init__(self, ops = None):
self.ops = ops or []
def __getitem__(self, item):
self.ops.append((True, item))
return self
def __getattr__(self, attr):
self.ops.append((False, attr))
return self
@staticmethod
def iterativeget(obj, ops):
for isitem, key in ops:
obj = obj[key] if isitem else getattr(obj, key)
return obj
def get(self, obj):
return self.iterativeget(obj, self.ops)
def set(self, obj, value):
isitem, key = self.ops[-1]
obj = self.iterativeget(obj, self.ops[:-1])
if isitem:
obj[key] = value
else:
setattr(obj, key, value)
def set_from_object(self, obj):
return lambda value: self.set(obj, value)
def set_to_value(self, value):
return lambda obj: self.set(obj, value)
@staticmethod
def object_value_setter(obj, value):
return lambda location: location.set(obj, value)
@staticmethod
def object_setter(obj):
return lambda location, value: location.set(obj, value)
@staticmethod
def value_setter(value):
return lambda location, obj: location.set(obj, value)
Давайте подготовим некоторые данные и сделаем несколько функций установки:
# since you can't set attributes on a normal dict, use a subclass
class MyDict(dict): pass
my_dict = MyDict({
'foo' : 'bar',
'subdict':{
'sub1' : 1,
'sub2' : 2
}
})
my_list = [1, 2]
x = 'x'
# we're going to set multiple things in my_dict to x, let's not repeat ourselves
set_my_dict_to_x = LocationProxy.object_value_setter(my_dict, x)
# we'll use set_to_x as you used it later on my_list
set_to_x = LocationProxy.value_setter(x)
Теперь давайте проверим их:
# you can assign a name to a setter to use multiple times
foosetter = LocationProxy()['foo']
# set normal dictionary items
set_my_dict_to_x(foosetter)
# And also set subdictionary items
set_my_dict_to_x(LocationProxy()['subdict']['sub1'])
# Set items that don't exist
set_my_dict_to_x(LocationProxy()['new_item'])
print 'my_dict', my_dict
# my_dict is a class, use the same function
set_my_dict_to_x(LocationProxy().myproperty)
print 'myproperty', my_dict.myproperty
# it works with lists
set_to_x(LocationProxy()[1], my_list)
print 'my_list', my_list