0

我正在尝试改进我的程序,使其符合良好的编程实践。因此,我正在寻找有关我编写某些东西的方式是否是一种好方法的建议。

我有一个名为 dbfunctions.py 的模块,我在其中定义了:

dbparams = {
    'dbname': 'qualitysimparams',
    'tablename': 'qualityparams',
    'tablecols': ('numpeople', 'numreviews', 'prophunters', 
                  'utility_funcform', 'goods'
    )

和一个功能:

def obtainid_ifrecord(dbname, tablename, tablecols, values):
    '''Checks if there already exists a record with given <values>. 
    If so, returns the id of that record, otherwise returns zero.'''
    con, c = connecttodb()
    q1 = "use {0}".format(dbname)
    c.execute(q1)
    q2p1 = "select id from {0} ".format(tablename)
    q2p2 = "where " + " = %s and ".join(tablecols) + " = %s"
    q2 = q2p1 + q2p2    
    c.execute(q2, values)
    res = c.fetchall()
    c.close()
    con.close()
    if res:
        return res[-1][0]
    else:
        return 0

除了上述两个之外,还有其他函数和变量,但与本文无关。

在另一个文件中,我有一个功能:

def checkif_paramcomboexists(numpeople, numreviews, prophunters, 
                             utility_funcform, goods):
    '''Check in the database if the simulation has been run with the 
    specified parameters. If so return the id of that run.
    '''
    goodsjson = sjson.dumps(goods)

    # paramvalues: in same order as listed in dbf.dbparams['tablecols']
    paramvalues = (numpeople, numreviews, prophunters, 
                   utility_funcform, goodsjson)

    id = dbf.obtainid_ifrecord(dbf.dbparams['dbname'],
                               dbf.dbparams['tablename'], 
                               dbf.dbparams['tablecols'],
                               paramvalues)
    return id 

在我看来, paramvalues在函数中的变量中硬编码变量名称checkif_paramcomboexists并不是一个好习惯。如果稍后我出于任何原因更改 dbfunctions.dbparams['tablecols'] 中的变量顺序,checkif_paramcomboexists函数将失败(并且可能会根据数据类型静默失败)。解决此问题的一种方法是定义:

paramvalues = [eval(x) for x in dbf.dbparams['tablecols']]

但是我听说通常使用它是一种不好的做法eval(尽管我不知道为什么以及何时可以使用它)。我的问题是:

(i) 就我所关心的问题而言,我编写此代码的方式可以吗?我认为答案是否定的,但只是想在这里与专家核实一下。(ii) 使用eval我所指出的可接受的解决方案吗?(iii) 如果对 (ii) 的回答是“否”,有什么替代方案?

感谢您阅读本文。

4

2 回答 2

3

这种情况确实需要一个对象。您在 2 个地方复制了关于特定数据库表的本质上的实例信息,因此将这两个函数用于具有属性的某种数据库表接口对象的方法中是有意义的tablecols,然后self.tablecols在这两种方法中使用。

于 2012-12-19T14:43:23.913 回答
3

你说的硬编码不是很好,绝对远离eval. 如果您不想使用*argsor**kwargs(顺便说一句,这是更好的选择),您可以使用该inspect模块来做您想做的事情。

import inspect, collections
def checkif_paramcomboexists(numpeople, numreviews, prophunters, 
                             utility_funcform, goods):

    ...

    temp = inspect.getargvalues(inspect.currentframe())
    args = temp[0]
    valuedict = temp[-1]
    ordered_args_dict = collections.OrderedDict(sorted(valuedict.items(), key=lambda x: args.index(x[0])))
    paramvalues = ordered_args_dict.values()

    ...

基本上,这里发生的事情是为inspect.getargvalues(inspect.currentframe())您提供一个对象,其中第一项是参数名称的正确排序列表,最后一项是参数名称和值的字典。然后,我们通过从字典中获取参数名称/值映射并根据列表顺序对其进行排序来创建一个有序字典。

你最终得到的是一个OrderedDict具有所有参数及其值的参数,而且它们的顺序也正确。这样,您仍然可以选择按名称(例如,ordered_args_dict['numpeople'])来引用它们,但是如果您仍然可以按照您想要的顺序获取所有值ordered_args_dict.values(),这将为您提供您正在寻找的输出paramvalues:正确排序参数列表,无论名称是什么。

于 2012-12-19T15:38:55.207 回答