Python 如何递归转换类实例的属性
我有一门课:Python 如何递归转换类实例的属性,python,Python,我有一门课: class Foo(object): def __init__(self, coord_tpl, coord_list, coord_dict, blah): # a single coord tuple # e.g. ((1, 2), (11, 22)) self.coord_tpl = coord_tpl # a list of coord tuple # e.g. [((1, 2),
class Foo(object):
def __init__(self, coord_tpl, coord_list, coord_dict, blah):
# a single coord tuple
# e.g. ((1, 2), (11, 22))
self.coord_tpl = coord_tpl
# a list of coord tuple
# e.g. [((1, 2), (11, 22)), ((3, 4), (33, 44))]
self.coord_list = coord_list
# a dict, whose value is a list of coord tuple
# e.g. { 0: [((1, 2), (11, 22)), ((3, 4), (33, 44))],
# 1: [((5, 6), (55, 66)), ((7, 8), (77, 88))] }
self.coord_dict = coord_dict
# some non-coord attributes
self.blah = blah
我还有一个轴翻译功能:coord\u translate
:
def coord_translate(old_coord):
# apply some translation logic to old_coord (x_o, y_o)
new_coord = ...
return new_coord
问题
我有一个Foo实例Foo:
foo = Foo(...)
如何翻译坐标属性(foo.coord\u tpl
、foo.coord\u list
和foo.coord\u dict
),而其他属性(foo.blah
)保持不变,使用coord\u translate
,以更优雅的方式,而不是递归地手工制作翻译逻辑
更新
确实存在以属性形式存在的递归结构:首先是简单的坐标元组,然后是坐标元组列表,最后是坐标元组列表
要执行转换逻辑,我可以递归地反映每个属性的类型,并应用coord_translate
:
for k, v in foo.__dict__.items():
if isinstance(v, tuple):
setattr(foo, k, (coord_translate(v[0]), coord_translate(v[1])))
elif isinstance(v, list):
for c in v:
...
elif isinstance(v, dict):
...
我想知道是否还有其他一些策略可以做到这一点,而不是使用像
if-isinstace(…)…elif-isinstace(…)。。。其他的
在C++等许多其他语言中,你可以重载函数(定义3个函数,叫做COORDION翻译,但每个函数接受不同的数据类型)
因为python是一种强类型的动态语言,我不知道有什么方法可以做到这一点
你可以用try,但据我所知
a) 不良风格
b) 不比您当前的解决方案好
def coord_translate(self, input):
try:
coord_translate_dict(input)
except ValueError:
coord_translate_list(input)
在我看来,最干净的解决方案是使用单一数据类型,并将每个输入转换为与此类型匹配的数据类型——我非常确定已经有库来处理此问题
另一种方法是这样的:
def coord_translate_dict(self, dict):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate_list(self, list):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate_tuple(self, tuple):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate(self, input):
if not coord_translate_dict(input) and not coord_translate_list(input):
coord_translate_tuple(input)
在C++等许多其他语言中,你可以重载函数(定义3个函数,命名为COODRION EXTION,但每个函数接受不同的数据类型) 因为python是一种强类型的动态语言,我不知道有什么方法可以做到这一点
你可以用try,但据我所知 a) 不良风格 b) 不比您当前的解决方案好def coord_translate(self, input):
try:
coord_translate_dict(input)
except ValueError:
coord_translate_list(input)
在我看来,最干净的解决方案是使用单一数据类型,并将每个输入转换为与此类型匹配的数据类型——我非常确定已经有库来处理此问题
另一种方法是这样的:
def coord_translate_dict(self, dict):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate_list(self, list):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate_tuple(self, tuple):
# apply some translation logic
try:
# do your stuff
return True
except:
return False
def coord_translate(self, input):
if not coord_translate_dict(input) and not coord_translate_list(input):
coord_translate_tuple(input)
您可以尝试:
from abc import ABC, abstractmethod
from collections import defaultdict
class CoordType(ABC):
registry_by_instance = defaultdict(list)
@abstractmethod
def coord_translate(self):
pass
@classmethod
def apply_coord_translate(cls, instance):
for attr in cls.registry_by_instance(instance):
attr.coord_translate()
class CoordTpl(CoordType):
def __init__(self, creation_instance, coord_tpl):
self.coord_tpl = coord_tpl
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class CoordList(CoordType):
def __init__(self, creation_instance, coord_list):
self.coord_list = coord_list
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class CoordDict(CoordType):
def __init__(self, creation_instance, coord_dict):
self.coord_dict = coord_dict
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class Foo(object):
def __init__(self, coord_tpl, coord_list, coord_dict, blah):
# a single coord tuple
# e.g. ((1, 2), (11, 22))
self.coord_tpl = CoordTpl(self.coord_tpl)
# a list of coord tuple
# e.g. [((1, 2), (11, 22)), ((3, 4), (33, 44))]
self.coord_list = CoordList(self, coord_list)
# a dict, whose value is a list of coord tuple
# e.g. { 0: [((1, 2), (11, 22)), ((3, 4), (33, 44))],
1: [((5, 6), (55, 66)), ((7, 8), (77, 88))] }
self.coord_dict = CoordDict(self, coord_dict)
# some non-coord attributes
self.blah = blah
def coord_translate(self):
CoordType.coord_translate(self)
您可以尝试:
from abc import ABC, abstractmethod
from collections import defaultdict
class CoordType(ABC):
registry_by_instance = defaultdict(list)
@abstractmethod
def coord_translate(self):
pass
@classmethod
def apply_coord_translate(cls, instance):
for attr in cls.registry_by_instance(instance):
attr.coord_translate()
class CoordTpl(CoordType):
def __init__(self, creation_instance, coord_tpl):
self.coord_tpl = coord_tpl
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class CoordList(CoordType):
def __init__(self, creation_instance, coord_list):
self.coord_list = coord_list
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class CoordDict(CoordType):
def __init__(self, creation_instance, coord_dict):
self.coord_dict = coord_dict
CoordType.registry_by_instance[creation_instance].append(self)
def coord_translate(self):
# your code to translate
class Foo(object):
def __init__(self, coord_tpl, coord_list, coord_dict, blah):
# a single coord tuple
# e.g. ((1, 2), (11, 22))
self.coord_tpl = CoordTpl(self.coord_tpl)
# a list of coord tuple
# e.g. [((1, 2), (11, 22)), ((3, 4), (33, 44))]
self.coord_list = CoordList(self, coord_list)
# a dict, whose value is a list of coord tuple
# e.g. { 0: [((1, 2), (11, 22)), ((3, 4), (33, 44))],
1: [((5, 6), (55, 66)), ((7, 8), (77, 88))] }
self.coord_dict = CoordDict(self, coord_dict)
# some non-coord attributes
self.blah = blah
def coord_translate(self):
CoordType.coord_translate(self)
我个人避免类型转换和“属性魔法”(我被太多的bug咬了一口,并且盯着不可理解的间接指令看了太久),我更喜欢让一切尽可能明确和直接 我将定义几个辅助函数:
def coord_translate(old_coord):
# Dummy implementation
x,y = old_coord
return (x+1, y+1)
def translate_tuple(tpl):
return tuple(map(coord_translate, tpl))
def translate_list(ls):
return list(map(translate_tuple, ls))
def translate_dict(dct):
return dict([(k, translate_list(v)) for (k,v) in dct.items()])
然后写
def translate(self):
self.coord_tpl = translate_tuple(self.coord_tpl)
self.coord_list = translate_list(self.coord_list)
self.coord_dict = translate_dict(self.coord_dict)
当然,如果愿意的话,您可以将这些助手函数包装在类型切换函数中。我个人避免类型切换和“属性魔法”(我被太多的bug所困扰,并且盯着不可理解的间接指令看了太久),并且更喜欢尽可能地保持所有内容的明确和直接 我将定义几个辅助函数:
def coord_translate(old_coord):
# Dummy implementation
x,y = old_coord
return (x+1, y+1)
def translate_tuple(tpl):
return tuple(map(coord_translate, tpl))
def translate_list(ls):
return list(map(translate_tuple, ls))
def translate_dict(dct):
return dict([(k, translate_list(v)) for (k,v) in dct.items()])
然后写
def translate(self):
self.coord_tpl = translate_tuple(self.coord_tpl)
self.coord_list = translate_list(self.coord_list)
self.coord_dict = translate_dict(self.coord_dict)
当然,如果愿意,您可以将这些助手函数包装到类型切换函数中。轴平移是什么意思?你的意思是,翻译所有的x值,使它们是
x+dx
,例如。?你能添加你的类吗?否则就有点混乱了。@alkasm嗨,我用“轴平移”的定义更新了这个问题。我还不清楚这个平移。调用coord\u translate
时,是否要修改属于Foo
实例的所有坐标?请在代码中给出具体示例,说明Foo
对象的外观,以及调用该方法后希望它的外观。明确显示最终结果应该是什么。coord_translate是你的类Foo的一部分吗?如果不是,这可能是您正在寻找的干净解决方案^^@rusu_ro1请参阅问题更新。谢谢。轴平移是什么意思?你的意思是,翻译所有的x值,使它们是x+dx
,例如。?你能添加你的类吗?否则就有点混乱了。@alkasm嗨,我用“轴平移”的定义更新了这个问题。我还不清楚这个平移。调用coord\u translate
时,是否要修改属于Foo
实例的所有坐标?请在代码中给出具体示例,说明Foo
对象的外观,以及调用该方法后希望它的外观。明确显示最终结果应该是什么。coord_translate是你的类Foo的一部分吗?如果不是,这可能是您正在寻找的干净解决方案^^@rusu_ro1请参阅问题更新。谢谢。谢谢,这个方法很容易适应我当前的代码。谢谢,这个方法很容易适应我当前的代码。谢谢你这么好的解决方案。我喜欢这个主意!谢谢你这么好的解决方案。我喜欢这个主意!