【问题标题】:Passing keyword arguments and **kwargs to subfunction将关键字参数和 **kwargs 传递给子函数
【发布时间】:2018-06-16 09:48:21
【问题描述】:

我有一个用于执行 sql 脚本的子类。

def execute_script(self, script_path, **kwargs):
    pass # connect to db
    query = open(script_path, "r").read().format(**kwargs)
    pass # execute script and close connection

根据我要执行的操作类型,我有不同的包装函数,使用不同的关键字参数,例如

def create_job(self, **kwargs):
    self.execute_script("create_job.sql", **kwargs)

现在,这非常适合格式化我的 sql 脚本以包含我的关键字参数,例如我执行create_job(job_name='foo')。该脚本获取job_name 并使用上面指出的.format()-方法将其放入我的sql 脚本中。

但是,随着 sql 脚本变长,需要传入更多参数,我可能很难准确记住需要传递哪些参数,因此我想从 *kwargs 切换到显式关键字参数,像这样:

def create_job2(self, job_name, **kwargs):
    self.execute_script("create_job.sql", **kwargs)

但是,这给我带来了以下错误:

KeyError: 'job_name'

所以,我在子函数中包含了job_name,认为execute_script() 中的**kwargs 参数意味着我可以将任意数量的关键字参数传递给函数。 然而,

def create_job3(self, job_name, **kwargs):
    self.execute_script("create_job.sql", job_name, **kwargs)

结果

TypeError: execute_script() takes exactly 2 arguments (3 given)

如果我省略了子函数 execute_script() 的 **kwargs 参数,也会发生同样的错误

我的问题:如何修改 execute_script() 函数,以便我可以将 any 关键字参数传递给包装函数?

或者(这实际上是首选),我可以离开**kwargs-connotation,而是使用文档字符串或任何其他机制来提醒我需要传递的参数(我我指的是弹出一个框并突出显示所需的参数,如 Sublime Text 或 PyCharm 正在做的)?

【问题讨论】:

  • 使用这种方法很容易引入sql注入漏洞。您可能想看看 prepared statements 以防止这种情况发生。
  • 谢谢,我已经阅读了类似的内容并更改了我的代码以使用首选方式 `cursor.execute(query, values) - 我想这就是您所指的?
  • 没错,不要自己格式化 sql 查询,即不要对 sql 使用 str.format 或旧的 % 字符串格式化。
  • @Wombatz 谢谢,已从字符串执行中删除。

标签: python python-2.7 function keyword-argument


【解决方案1】:

使用此代码:

def create_job2(self, job_name, **kwargs):
    self.execute_script("create_job.sql", **kwargs)

def execute_script(self, script_path, **kwargs):
    pass # connect to db
    query = open(script_path, "r").read().format(**kwargs)
    pass # execute script and close connection

job_name 参数在create_job 内部“丢失”,并且没有传递给execute_scriptkwargs 只是一个您可以编辑的映射:

def create_job2(self, job_name, **kwargs):
    kwargs['job_name'] = job_name
    self.execute_script("create_job.sql", **kwargs)

但由于您实际上并未在 create_job 中使用 job_name,因此我认为以这种方式拆分它没有帮助(并且会坚持您对 create_job 的原始定义)。

KeyError 表示后面的某些东西期待命名参数 job_name,或者您正试图将其从 kwargs 字典中提取出来。

正如您所指出的,“记住”(或被提醒)参数的一种方法是在方法定义中明确列出它们。

但另一个是新建一个类,例如:

class Job:
    def __init__(self, name, foo, bar, ...):
        self.name = name
        ...

所以你在一个地方有一堆参数可能很烦人并且难以维护,但它只在一个地方并且不会在你的每个函数中重复。

然后你在函数/方法之间传递一个 Job 对象,它们访问 Job 实例属性。

根据您的结构,您甚至可以实现Job.execute() 方法。

【讨论】:

  • 感谢您的回答。也许我的问题不够清楚;我不知道哪些参数将传递给 execute_script(),因为它取决于我正在执行的 sql 脚本。像您建议的那样编辑 kwargs-mapping 确实有效,但是,一旦我超过 5 个变量,该函数将变得非常笨重。您知道执行此操作的更优雅的方式吗?
猜你喜欢
  • 2012-04-09
  • 2011-06-03
  • 2010-09-24
  • 1970-01-01
  • 2017-08-01
  • 2013-06-29
  • 2016-12-13
  • 2021-09-11
相关资源
最近更新 更多