Python 装饰师不是';不要传递论点?
我一直致力于将n维数组序列化为一维“数组”数据库:Python 装饰师不是';不要传递论点?,python,sqlite,functional-programming,decorator,pysqlite,Python,Sqlite,Functional Programming,Decorator,Pysqlite,我一直致力于将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)): f
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:
[]
输出取消注释#返回函数(*args,**kwargs)
:
不幸的是,用计数器装饰的insert
函数似乎没有正确地传递参数
我做错了什么?一个问题似乎是,您正在使用*args
展开args
参数,但您将游标作为该参数的值传入,而没有将其包装在元组中。因此,您最终的调用是insert(“foo”,光标)
,而您似乎希望它是insert(“foo”,光标)
。尝试执行传递多个([[“foo”、“bar”]、“pew”]、插入(游标),)
我认为发生的情况是,当您执行此操作时,您的test\u var\u args
函数正在使用游标对象(这显然是可编辑的),因此在后续调用realinsert
函数时,不会留下更多要展开的参数
回答后编辑:您不想将v
传递给您的func
呼叫吗?您编写的insert函数接受两个参数,v
和cursor
,但您只使用cursor
调用它。为什么要包装insert
?额外的论点应该做什么?您不在包装器中使用它,也不将它传递给底层函数,那么它的用途是什么呢?有两件事:首先,在包装器()中:
您已将第一个参数映射到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\u many()
时,给了它一个cursor
对象作为args
参数。这将微妙地失败。要解决此问题,您可以删除splat操作符*
,或者,更好的选择是,在调用pass\u many
时,可以将游标
对象包装在元组中,如下所示:
pass_many([["foo", "bar"], "pew"], insert, (cursor,))
这仍然会给出一个错误“没有这样的表:wordlist”,但这实际上是因为您还没有定义这样的表。('wordlist'是insert()
的默认参数)根据@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])
装饰器中的函数调用被注释掉了吗?是的,这样调试test\u var\u args
函数就可以一直运行insert
来显示哪些args在何时出现。您能提供一个更简单的测试用例吗?在一个简单的无操作函数(def func(*args,**kwargs):pass
)上使用decorator会显示问题,这将是理想的。此外,最好能准确地了解出了什么问题——例如,列出您期望的输出和实际得到的输出。您如何知道它不起作用?你期望什么样的产出?你得到了什么?如果您得到一个错误,它是什么?用当前输出更新,输出取消注释return func(*args,**kwargs)
和预期输出。谢谢,给了我一个稍微好一点的结果:TypeError:insert()至少接受2个参数(1个给定)
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)
pass_many([["foo", "bar"], "pew"], insert, (cursor,))
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])