Python 如何重构以避免传递函数?

Python 如何重构以避免传递函数?,python,pandas,dataframe,refactoring,Python,Pandas,Dataframe,Refactoring,我目前有一些代码,可以使用pandas数据帧从多个源获取和处理数据。其目的是让用户创建一个类的实例(称之为dbase),该类提供了从API查询中获取和存储数据等方法。我是通过允许用户定义自己的函数来在dbase中格式化值来实现这一点的,但我发现,我倾向于以令人困惑的方式将这些用户定义的函数传递给其他几个函数。我认为,对于那些知道自己在做什么的人来说,这肯定是一个明显的错误,但我还没有想出更好的方法让用户控制数据 API查询是目前最糟糕的例子。假设我想从服务器获取一个名称。现在,我做了如下的事情,

我目前有一些代码,可以使用pandas数据帧从多个源获取和处理数据。其目的是让用户创建一个类的实例(称之为
dbase
),该类提供了从API查询中获取和存储数据等方法。我是通过允许用户定义自己的函数来在
dbase
中格式化值来实现这一点的,但我发现,我倾向于以令人困惑的方式将这些用户定义的函数传递给其他几个函数。我认为,对于那些知道自己在做什么的人来说,这肯定是一个明显的错误,但我还没有想出更好的方法让用户控制数据

API查询是目前最糟糕的例子。假设我想从服务器获取一个名称。现在,我做了如下的事情,其中用于转换名称的用户定义函数在被调用之前通过了其他三个函数

# file with code for api interaction
def submitter(this_query, dbase, name_mangler):
    new_data = api.submit(this_query)
    new_dbase_entry = name_mangler(new_data)
    # in reality there is much more complicated data transformation here
    dbase.update(new_dbase_entry)

def query_api(dbase, meta, name_mangler):
    queries = make_query_strings(dbase, meta)
    # using pandas.DataFrame.apply() here to avoid a for loop
    queries.apply(lambda x: submitter(x, dbase))
然后,用户将执行类似的操作

import dbase

def custom_mangler(name):
    # User determines how to store the name in dbase
    # for instance this could take "Grace Hopper" to "hopper"
    return(mangled_name)

my_dbase = dbase.dbase()
# meta defines what needs to be queried and how the remote
# data should get processed into dbase
meta = {stuff} 
my_dbase.get_remote_data(meta, custom_mangler)

我发现在这里很难遵循我自己的代码,因为函数的定义可以从调用它们的第一个点广泛地分开。我应该如何重构来解决这个问题?(这种方法是否因为其他原因违反了公认的编码模式?

从您发布的内容推断上下文有点困难,所以对此持保留态度。一般概念仍然适用。还可以看看这个问题,因为这个问题可能更适合那个网站

我想到两件事

  • 尽量给你的函数/类/变量起更好的名字
  • 想想正交性
  • 好名声 从用户的角度考虑这一点
    dbase
    对于模块或类来说都不是一个非常具有描述性的名称
    meta
    根本没有告诉我dict应该包含什么
    mangler
    告诉我字符串已更改,但没有说明字符串来自何处或应如何更改

    好名字是很难的,但花时间让他们深思熟虑是值得的。它总是在描述性和过于冗长之间进行权衡。如果你想不出一个明确的含义而不占用太多的空间,那么考虑一下你的API是否过于复杂。总是考虑终端用户的名字以及将来阅读/维护代码的程序员。

    正交性 遵循Unix的“只做一件事,把它做好”的口号,如果我们将不同的任务分成不同的函数,而不是让一个函数完成所有任务,那么有时API会更简单、更灵活

    在编写代码时,我认为“这个函数需要做什么才能有用?”

    在你的例子中

    my_dbase.get_remote_data(meta, custom_mangler)
    
    获取远程数据
    不仅获取数据,还处理数据。这可能会让用户感到困惑。在这个函数的幕后发生了很多事情,从函数名上看并不明显

    对此,可能更适合使用单独的函数调用。假设您正在查询气象服务器有关温度和降雨量的信息

    london_weather_data = weatheraggrigator.WeatherAggrigator()
    reports = london_weather_data.fetch_weather_reports(sources=[server_a, server_b])
    london_weather_data.process_reports(reports, short_name_formatter)
    
    是的,输入的时间更长,但作为一个用户,这是一个很大的改进,因为我知道我得到了什么


    最终,您需要决定在何处拆分任务。以上内容可能对您的应用程序没有意义。

    谢谢您的宝贵建议。这里的名字完全是为这个例子编造的。这是迄今为止我试图自己编写代码的最复杂的项目,我花了相当长的时间在文章中提取骨架,这样我就可以问一件事,而不是让人们费力地浏览所有涉及的其他组件(我想这意味着正交性应该是优先考虑的)。
    london_weather_data = weatheraggrigator.WeatherAggrigator()
    reports = london_weather_data.fetch_weather_reports(sources=[server_a, server_b])
    london_weather_data.process_reports(reports, short_name_formatter)