0

我一直致力于将 n 维数组序列化为一维“数组”数据库:

from collections import Iterable, Mapping
import sqlite3

def pass_many(vals, some_funct, args=()):
    if not vals:
        return
    if isinstance(vals, Iterable) and not isinstance(vals, (basestring, Mapping)):
        for v in vals:
            pass_many(v, some_funct, args)
    else:
        some_funct(vals, *args)

def counter(func):
    def wrapper(v, *args, **kwargs): # added 'v' arg to no avail
        wrapper.count = wrapper.count + 1
        test_var_args(v, *args, **kwargs)
        #return func(*args, **kwargs)
    wrapper.count = 0

    return wrapper

def test_var_args(farg, *args):
    print "formal arg:", farg
    for arg in args:
        print "another arg:", arg

@counter
def insert(val, cursor, table="wordlist", logfile="queries.log"):
    print val, cursor, table, logfile
    if val:
        if isinstance(val, (basestring, Mapping)):
            val = '\"' + val + '\"'
        else: val = str(val)
        query = "insert into tablename values (?);".replace('tablename', table).replace('?', val)
        #if logfile: to_logfile(query + '\n', logfile)
        cursor.execute(query)

if __name__ == '__main__':
    connection = sqlite3.connect('andthensome.db')
    cursor = connection.cursor()
    cursor.execute("create table array (word text);")
    pass_many([["foo", "bar"], "pew"], insert, cursor)
    connection.commit()
    cursor.execute("select * from array;") # wrapped select function omitted for brevity
    print "insert() was called", insert.count, "times, and db now contains:\n", cursor.fetchall()
    cursor.close()

输出:

formal arg: foo
formal arg: bar
formal arg: pew
insert() was called 3 times, and db now contains:
[]

输出取消注释#return func(*args, **kwargs)

formal arg: foo
Traceback (most recent call last):
    Line 42, in <module>
        pass_many([["foo", "bar"], "pew"], insert, cursor)
    Line 9, in pass_many
        pass_many(v, some_funct, args)
    Line 9, in pass_many
        pass_many(v, some_funct, args)
    Line 11, in pass_many
        some_funct(vals, *args)
    Line 17, in wrapper
        return func(*args, **kwargs)
    TypeError: insert() takes at least 2 arguments (0 given)

预期输出(省略调试功能):

insert() was called 3 times, and db now contains:
["foo","bar","pew"]

insert不幸的是,用装饰的函数似乎没有counter正确传递参数。

我究竟做错了什么?

4

3 回答 3

2

一个问题似乎是您正在使用*args来扩展您的args论点,但是您cursor作为该论点的值传入而没有将其包装在一个元组中。因此,您最终的电话是insert("foo", *cursor),当您似乎想要它时insert("foo", cursor)。尝试做pass_many([["foo", "bar"], "pew"], insert, (cursor,))

我认为正在发生的事情是,当您这样做时,您的函数正在使用游标对象(这显然是可迭代的),因此在随后调用真实函数test_var_args时不再留下要扩展的参数。insert

在您回复后编辑:您真的不想传递v给您的func电话吗?您编写的插入函数需要两个参数,vcursor,但您只用 . 调用它cursor。你为什么要包装insert?额外的参数应该做什么?你没有在包装器中使用它,也没有将它传递给底层函数,那么它的目的是什么?

于 2012-06-10T07:47:12.127 回答
0

有几件事:首先,在wrapper()

def counter(func):
    def wrapper(v, *args, **kwargs): # added 'v' arg to no avail
        wrapper.count = wrapper.count + 1
        test_var_args(v, *args, **kwargs)
        return func(*args, **kwargs)
    ...

您已将第一个参数映射到v,但没有将其传递给真实的func。最好彻底删除。

其次,也是最重要的:

def pass_many(vals, some_funct, args=()):
    if not vals:
        return
    if isinstance(vals, Iterable) and not isinstance(vals, (basestring, Mapping)):
        for v in vals:
            pass_many(v, some_funct, args)
    else:
        some_funct(vals, *args)

请注意,当您调用 时some_funct(),您正在解构args参数。问题是,当你调用 时pass_many()你给了它一个cursor对象作为args参数。这将巧妙地失败。要解决此问题,您可以删除 splat 运算符*,或者更好的选择,您可以cursor在调用时将对象包装在一个元组中pass_many,如下所示:

pass_many([["foo", "bar"], "pew"], insert, (cursor,))

这仍然会给出“没有这样的表:wordlist”的错误,但这实际上是因为你还没有定义这样的表。('wordlist' 是 的默认参数insert()

于 2012-06-10T08:10:32.560 回答
0

根据@BrenBarn 的建议,我已将其修改为:

def counter(func):
    def wrapper(v, *args, **kwargs):
        wrapper.count = wrapper.count + 1
        test_var_args(v, *args, **kwargs)
        return func(v, *args, **kwargs)
    wrapper.count = 0

    return wrapper

pass_many([["foo", "bar"], "pew"], insert, [cursor])
于 2012-06-10T10:02:56.437 回答