Python:如何将要处理的对象成员(可能嵌套更深)传递给函数?

Posted

技术标签:

【中文标题】Python:如何将要处理的对象成员(可能嵌套更深)传递给函数?【英文标题】:Python: how to pass to a function which object member (possibly nested deeper down) to work on? 【发布时间】:2020-02-23 12:30:25 【问题描述】:

背景

我有一个包含列表成员 x 和 y 的对象字典:

plot_data._trace_d = 
    TraceType.A: 
        'abc': TraceData(x=[ 0, 1, 2, 3 ], y=[10, 11, 12, 13])
        'def': TraceData(x=[100, 101, 102, 103], y=[110, 111, 112, 113])
    ,
    TraceType.B: 
        'abc': TraceData(x=[1000, 1001, 1002], y=['x', 'y', 'z']),
        'def': TraceData(x=[1010, 1011, 1012], y=['xx', 'yy', 'zz'])
    

为了符合我的绘图工具(情节),我需要展平每条迹线,以便我有以下形式的列表:

# TraceType.A
x = [0, 1, 2, 3, 100, 101, 102, 103]
y = [10, 11, 12, 13, 110, 111, 112, 113]
plot(x, y, ...)

# TraceType.B
x = [1000, 1001, 1002, 1010, 1011, 1012]
y = ['x', 'y', 'z', 'xx', 'yy', 'zz']
plot(x, y, ...)

我目前的解决方案

使用字符串传递要展平的成员。

class TraceData:
    def __init__(self, x, y):
        x = []
        y = []
    # ...

class PlotData:
    def __init__(self):
        self._trace_d = 
            TraceType.A: TraceData(),
            TraceType.B: TraceData(),
        
    # ...
    def flatten_trace_data(self, trace_type, dimension): # HERE! dimension is a string
        """For a trace type, get the lists for all nodes and concatenate them
        into a single list. Useful to build a single Plotly trace for multiple
        nodes."""
        flat_list = []
        for node, td in self._trace_d[trace_type].items():
            print("Flattening node %r dim %s" % (node, dimension))
            flat_list += getattr(td, dimension)

        return flat_list

plot_data = PlotData()
# ...
x = plot_data.flatten_trace_data(TraceType.A, 'x')

我想要什么

把维度参数给成字符串感觉很脏,感觉matlaby。有没有办法告诉成员函数对成员的给定参数执行某些操作?像这样的:

x = plot_data.flatten_trace_data(TraceType.A, TraceData.x)

我试过这个,为什么不呢,但是TraceData 没有属性'x'

什么是告诉展平函数要展平的对象的哪个维度(在嵌套的嵌套字典中)的优雅方法?

【问题讨论】:

使用getattrsetattr? @juanpa.arrivillaga 它仍然使用字符串,但绝对是一个很好的改进。我将更新代码以使用它。 【参考方案1】:

用 getattrib 试试这样的东西。


def flatten_trace_data(self, trace_type, dimension):
"""For a trace type, get the lists for all nodes and concatenate them into a single list. Useful to build a single Plotly trace for multiple nodes."""
    flat_list = [] 
    for node, l in self._trace_d[trace_type].items():
        print("Flattening node %r dim %s" % (node, dimension))
        flat_list += getattr(l, dimension)
    return flat_list

编辑 1,使用属性

class PlotData: 
    def __init__(self): 
        self._trace_d =  
           TraceType.A: TraceData(), 
           TraceType.B: TraceData(),  # ... 

    @property
    def x_A(self):
        flat_list = [] 
     for node, td in self._trace_d[TraceType.A].items():
         flat_list += td.x
      return flat_list

编辑 2

你想要实现的是这样的。

plot_data = PlotData()
x = plot_data.A.x
y = plot_data.A.y

这将是更 Pythonic 的方式。

为此,您需要重新考虑 TaceData、TraceType 和 PlotData 中的每个类。

【讨论】:

有趣的是,在@juanpa.arrivillaga 发表评论后,我刚刚通过此更改编辑了我的问题。但是flatten_trace_data 的参数仍然是一个字符串,我不确定它是否非常pythonese。 @Gauthier 是的,很有趣。据我所知,是的,它是 pytonic 因为这是使用函数执行此操作的唯一方法。但是,您可以在 PlotData 类中创建属性来获取字符串。我会更新我的awser。 如果它是pythonic,那么它就是......我刚刚看到getattr无论如何都需要一个字符串。注意:您的答案第一行的错字,getattrib 似乎不存在。 使用属性强制我创建 n(TraceType) * n(dimensions) 函数? @Gauthier 是的,完全正确。这不是很合适,但是您可以想象创建一个 TraceD 类。

以上是关于Python:如何将要处理的对象成员(可能嵌套更深)传递给函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 的多处理中创建嵌套共享对象?

合并数组中的两个对象,其中一个对象的键嵌套比另一个对象更深,位于 Mongo DB 的同一文档中

将 YAML 加载为嵌套对象而不是 Python 中的字典

面向对象---成员,嵌套(建模)

C#:循环遍历嵌套结构的成员对象

React:使用 Hooks 为深度嵌套对象设置状态