在Python中为字符串和列表编写通用函数

7 投票
9 回答
1692 浏览
提问于 2025-04-17 10:38

我刚开始学习编程,正在看一本叫《如何像计算机科学家一样思考:学习Python 3》的书。我能回答下面的问题,但我担心自己可能没理解其中的要点。

写一个函数(叫做insert_at_end),这个函数需要根据下面给出的两个参数,能够在所有三种情况下都正确返回结果:

test(insert_at_end(5, [1, 3, 4, 6]), **[1, 3, 4, 6, 5]**)
test(insert_at_end('x', 'abc'),  **'abcx'**)
test(insert_at_end(5, (1, 3, 4, 6)), **(1, 3, 4, 6, 5)**)

书中给了一个提示:“这些练习很好地说明了序列抽象是通用的,(因为切片、索引和连接都是非常通用的),所以可以编写适用于所有序列类型的通用函数。”

这个版本在网上找不到解决方案(至少我没找到),但我找到了一些人对之前版本(Python 2.7)的回答,他们是这样做的:

def encapsulate(val, seq):
    if type(seq) == type(""):
        return str(val)
    if type(seq) == type([]):
        return [val]
    return (val,)

def insert_at_end(val, seq): 
    return seq + encapsulate(val, seq)

看起来他们通过区分列表和字符串来解决这个问题……这和提示的意思是相反的。那么,有没有办法在不区分的情况下回答这个问题(以及大约10个类似的问题)呢?也就是说,不使用“type()”这个函数?

9 个回答

2

我觉得这个例子不太对称,也就是说,它让读者处理两种不同的情况:

  • 整数和列表
  • 字符串和字符串

在我看来,这个练习应该要求实现以下内容:

  • 列表和列表:insert_at_end([5], [1, 3, 4, 6])
  • 字符串和字符串:insert_at_end('x', 'abc')

这样的话,读者只需要处理两个使用相同类型的参数,这样提示就会更有意义。

3

我尽力而为:

def insert_at_end(val, seq):
    t = type(seq)
    try:
        return seq + t(val)
    except TypeError:
        return seq + t([val])

这段代码会尝试创建一个和 type(seq) 一样类型的序列。如果 val 不是可以迭代的东西,它会生成一个列表并把它们连接在一起。

1

这不是一个解决方案,而是解释为什么一个真正优雅的解决方案似乎不可行。

  • + 用来连接序列,但只能连接同类型的序列。
  • 传给 insert_at_end 的第一个参数是“标量”,所以你必须把它们转换成第二个参数所要求的序列类型。
  • 为了做到这一点,你不能简单地用标量参数调用序列构造函数来创建一个只有一个元素的序列:比如 tuple(1) 是不行的。
  • str 的工作方式和其他序列类型不同:tuple(["a"]) 结果是 ("a",)list(["a"]) 结果是 ["a"],但 str(["a"]) 的结果是 "['a']",而不是 "a"

这使得在这种情况下 + 变得无用,尽管你可以很容易地干净地构造出所需类型的序列,而不需要使用 instanceof,只需用 type() 就可以了。

你也不能使用切片赋值,因为只有列表是可变的。

在这种情况下,@Hamish 的解决方案看起来是最干净的。

撰写回答