Python,如何将元组中的元素作为参数传入函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/inter_peng/article/details/82972596

本文由Markdown语法编辑器编辑完成。

1. 需求:

现在有一个Python的需求需要实现:

就是实现连接一次数据库,就能够执行多条SQL语句,而且这个SQL语句是需要通过调用者将每一次执行的参数传入进来,组合成一条完整的SQL语句再去执行。

经过初步研究,传入参数时,通过数组的形式,数组中的每一个元素则是一个元组tuple(因为SQL中需要填入的参数可能是多个,所以需要通过元组的形式传入)。

比如SQL语句的形式为:
basic_sql = ‘SELECT * FROM series se where se.body_part like “%{}%” and se.modality = “{}”’
在这条SQL中,有两个变量需要传入,分别用{}表示,一个是序列的body_part, 一个是序列的modality。准备传入的参数为:
[(‘Chest’, ‘CT’), (‘Lung’, ‘MRI’), (‘Leg’, ‘DR’)]等。

希望通过以下的格式化函数,将参数传入:
SELECT * FROM series se where se.body_part like “%{}%” and se.modality = “{}”.format(param1, param2) 这样。

2. 函数实现:

虽然看起来这个需求非常明确,也比较简单。但是实现起来,还是花费了我好长的时间。究其原因,主要的困惑就是如何能够将这个参数传入到SQL中,并且去执行SQL。

2.1 思路一:

在基于需求中提到的那个解决思路,我希望是拼接字符串,将拼接后的整个字符串作为完整的SQL语句,然后执行生成结果。

def execute_multi_sql(self, sql, params_list):
	result_list = []
        try:
            self._db_connection = self._db_connection_pool.connection()
            self._db_cursor = self._db_connection.cursor()
			for params in params_list:
			    combined_sql = []
			    combined_sql.append(sql)
			    combined_sql.append('.format(')
			    combined_sql.append(','.join(map(str, params)))
			    combined_sql.append(')')
			    combined_sql = ''.join(combined_sql)
			    logger.debug("executing sql: %s" % combined_sql)
			    self._db_cursor.execute(combined_sql)
			    result = self._db_cursor.fetchall()
			    logger.debug(u"SQL语句已经被执行, 结果是:\n %s" % str(result))
			    result_list.append(result)
		except Exception as e:
            logger.exception(u"执行sql语句时,发生了错误: %s", e.message)
            raise
        finally:
            self._db_connection.close()
            return result_list

但是在执行这个函数的时候,会报异常,异常说明是:tuple out of bounds.
以下是问题产生的原因:

2.2 思路二:

通过google搜索,最终找到的解决方案是如下链接所示:
expanding tuples into arguments.
https://stackoverflow.com/questions/1993727/expanding-tuples-into-arguments

from DBUtils.PooledDB import PooledDB
import logging
......

    def execute_multi(self, sql, params_list):
        if not isinstance(params_list, list):
            raise Exception(u'传入参数要求是列表类型,请检查传入参数类型!')
        result_list = []
        try:
            self._db_connection = self._db_connection_pool.connection()
            self._db_cursor = self._db_connection.cursor()

            for params in params_list:
                # 将每一个元组中存的参数传入format中,替换sql中的变量值.
                # 如果数组中的元素不是元组,则sql中只有一个变量需要替换,将参数直接替换.
                if isinstance(params, tuple):
                    combined_sql = sql.format(*params)
                else:
                    combined_sql = sql.format(params)

                logger.debug("executing sql: %s" % combined_sql)
                self._db_cursor.execute(combined_sql)
                result = self._db_cursor.fetchall()
                logger.debug(u"SQL语句已经被执行, 结果是:\n %s" % str(result))
                if len(result) > 0:
                    result_list.append(result)
        except Exception as e:
            logger.exception(u"执行sql语句时,发生了错误: %s", e.message)
            raise
        finally:
            self._db_connection.close()
            return result_list

这段代码中,最主要的修改就是关于处理参数的部分. 由于传入的参数是一个数组,数组中的每一个元素是一个tuple, tuple内的元素个数是由第2个参数sql中需要传入的参数个数对应的。如上述需求中提到的,传入的sql中需要补充两个参数值,分别是body_part和modality, 因此数组中每一个tuple的长度也是2.
这样通过*tuple的方式,可以依次取出tuple中的每一个元素作为变量,传入前面的sql语句中,组成一个完整的sql语句。然后再调用db.execute, 便可以获取到查询结果.

猜你喜欢

转载自blog.csdn.net/inter_peng/article/details/82972596