我有一个函数,它将DB表的列表作为参数,并返回一个要在这些表上执行的命令字符串,例如:
pg_dump( file='/tmp/dump.sql',
tables=('stack', 'overflow'),
port=5434
name=europe)
应该返回类似的内容:
pg_dump -t stack -t overflow -f /tmp/dump.sql -p 5434 europe
这是使用tables_string='-t '+' -t '.join(tables)
完成的。
当使用以下函数调用函数时开始有趣:tables=('stackoverflow')
(字符串)而不是tables=('stackoverflow',)
(元组),它产生:
pg_dump -t s -t t -t a -t c -t k -t o -t v -t e -t r -t f -t l -t o -t w
-f /tmp/dump.sql -p 5434 europe
因为字符串本身正在迭代。
This SO question建议在类型上使用断言,但我不确定它是否足够Pythonic,因为它打破了鸭式约定。
任何见解?
亚当
答案 0 :(得分:6)
在这种情况下,断言这种类型似乎是合适的 - 处理一种常见的误用,因为鸭子打字似乎是合法的。
处理这种常见情况的另一种方法是测试字符串并将其作为特殊情况正确处理。
最后,您可以鼓励将表名作为位置参数传递,这会使这种情况不太可能:
def pg_dump(*tables, **kwargs):
file = kwargs['file']
port = kwargs['port']
name = kwargs['name']
...
pg_dump('stack', 'overflow', file='/tmp/dump.sql', port=5434, name='europe')
答案 1 :(得分:2)
您可以使用AB来断言对象是可迭代的但不是字符串:
from types import StringType
from collections import Iterable
assert isinstance(x, Iterable) and not isinstance(x, StringType)
答案 2 :(得分:1)
检测参数是序列(列表或元组)还是字符串的常见Python习惯用法是检查它是否具有__iter__
属性:
def func(arg):
if hasattr(arg, '__iter__'):
print repr(arg), 'has __iter__ attribute'
else:
print repr(arg), 'has no __iter__ attribute'
func('abc')
# 'abc' has no __iter__
func(('abc'))
# 'abc' has no __iter__
func(('abc',))
# ('abc',) has __iter__
当它不是一个序列时,通常将它改为一个以简化代码的其余部分(只需要处理一种事物)。在示例中,可以使用简单的arg = [arg]
完成。
答案 3 :(得分:0)
你能不使用列表而不是元组?
pg_dump( file='/tmp/dump.sql',
tables=['stack', 'overflow'],
port=5434,
name='europe')