7

我有一个函数,它获取数据库表列表作为参数,并返回要在这些表上执行的命令字符串,例如:

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

因为字符串本身正在被迭代。

这个 SO question建议在类型上使用断言,但我不确定它是否足够 Pythonic,因为它打破了鸭子类型的约定。

有什么见解吗?

亚当

4

4 回答 4

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')
于 2010-11-21T10:52:44.630 回答
2

您可以使用 ABC 断言对象是可迭代的但不是字符串:

from types import StringType
from collections import Iterable
assert isinstance(x, Iterable) and not isinstance(x, StringType)
于 2010-11-21T12:37:13.963 回答
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].

于 2010-11-21T11:02:10.940 回答
0

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

pg_dump( file='/tmp/dump.sql',
         tables=['stack', 'overflow'],
         port=5434,
         name='europe')
于 2010-11-21T10:49:53.607 回答