验证参数的Pythonic方法是序列而不是字符串

验证参数的Pythonic方法是序列而不是字符串,python,duck-typing,Python,Duck Typing,我有一个函数,它获取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\u string='-t'

我有一个函数,它获取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\u 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
因为字符串本身正在被迭代

建议在类型上使用断言,但我不确定它是否足够python,因为它打破了duck类型约定

有什么见解吗


Adam

你不能使用列表而不是元组吗

pg_dump( file='/tmp/dump.sql',
         tables=['stack', 'overflow'],
         port=5434,
         name='europe')

在这种情况下,断言类型似乎是合适的——处理一种常见的误用,因为duck类型似乎是合法的

处理这种常见情况的另一种方法是测试字符串,并将其作为特殊情况正确处理

最后,您可以鼓励将表名作为位置参数传递,这将减少出现这种情况的可能性:

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')

检测参数是序列(列表或元组)还是字符串的常用Python习惯用法是检查它是否具有
\uuu iter\uu
属性:

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]

来完成此操作,您可以使用ABCs断言对象是可编辑的,但不是字符串:

from types import StringType
from collections import Iterable
assert isinstance(x, Iterable) and not isinstance(x, StringType)

您指的是一个用户错误地使用了
('foo')
,而不是
('foo',)
,对吗?@orip这就是问题的关键:用户可能会犯这个错误,我想防止它发生。旁注:字符串没有
\iter\uuuuuu
属性是不一致的,在Python 3中已被更改。吉姆·布里松:我一直觉得这是不一致的,因为字符串在所有字符序列之后。知道一个好的PY3K成语吗?检查
type(arg)
是否有字符串方法,比如'lower`?您可以检查
notisinstance(foo,str)
如提问者链接到的问题中所建议的(
basestring
而不是
str
for Python<3)@orip:当然,可以键入check,但正如OP所指出的,这似乎不是很“Pythonic”。如果有一种通用的方法来检查某个东西是否是被字符串类型搞混的序列,那就太好了,
\uuuu iter\uuuu
测试在Python2中所做的,但在v3.+1中听起来像是“修复了”了。我想我将测试参数,并简单地将字符串转换为1元组。它会让用户更快乐,但并不能解决问题——如果用户传递字符串,它仍然会失败。