所以我像草一样绿色,从How to think like a computer scientist: Learn 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()”
答案 0 :(得分:2)
我说这个例子不是对称的,这意味着它要求读者处理两种不同的情况:
在我看来,练习应该要求实施:
在这种情况下,阅读器必须只使用两个使用相同序列类型的参数,并且提示更有意义。
答案 1 :(得分:2)
我尽力而为:
def insert_at_end(val, seq):
t = type(seq)
try:
return seq + t(val)
except TypeError:
return seq + t([val])
这将尝试创建type(seq)
的序列,如果val
不可迭代,则生成列表并连接。
答案 2 :(得分:1)
该问题是一个长列表之一,提示适用于所有这些问题。我认为编写encapsulate
函数可以重用insert_at_front
之类的函数是合理的,其余的实现是类型无关的。
但是,我认为encapsulate
的更好实现可能是:
def encapsulate(val, seq):
if isinstance(seq, basestring):
return val
return type(seq)([val])
使用更少的代码处理更多类型。
答案 3 :(得分:1)
这不是解决方案,而是解释为什么真正优雅的解决方案看起来不可能。
+
连接序列,但只连接相同类型的序列。insert_at_end
的值是'标量',因此您必须将它们转换为第二个参数所具有的序列类型。tuple(1)
不起作用。str
与其他序列类型的工作方式不同:tuple(["a"])
为("a",)
,list(["a"])
为["a"]
,但str(["a"]))
为"['a']"
而不是"a"
。这使得+
在这种情况下无效,即使您只需使用instanceof
就可以轻松地构建一个给定类型的序列,而不是type()
。
您也不能使用切片分配,因为只有列表是可变的。
在这种情况下,@ Hamish的解决方案看起来最干净。
答案 4 :(得分:0)
这个问题的挑战(在Python 2.7中,我现在正在测试3.2验证)是seq
的两种可能的输入类型是不可变的,并且你应该返回相同的类型传入。对于字符串,这不是一个问题,因为你可以这样做:
return seq + char
因为这将返回一个新字符串,它是输入序列和附加字符的串联,但这对列表或元组不起作用。您只能将列表连接到列表或将元组连接到元组。如果你想避免“类型”检查,你可以用这样的东西到达那里:
if hasattr(seq, 'append'): # List input.
seq.append(char)
elif hasattr(seq, 'strip'): # String input.
seq = seq + char
else: # Tuple
seq = seq + (char,)
return seq
这与实际检查类型确实没什么不同,但确实避免直接使用type
函数。
答案 5 :(得分:0)
此解决方案仍然需要一些单独的字符串代码而不是列表/元组,但它更简洁,不会检查特定类型。
def insert_at_end(val, seq):
try:
return seq + val
except TypeError: # unsupported operand type(s) for +
return seq + type(seq)([val])
答案 6 :(得分:0)
也许这更接近答案:
def genappend(x, s):
if isinstance(s, basestring):
t = s[0:0].join
else:
t = type(s)
lst = list(s)
lst.append(x)
return t(lst)
print genappend(5, [1,2,3,4])
print genappend(5, (1,2,3,4))
print genappend('5', '1234')
也可能存在完全由用户定义的序列类型。只要可以转换为列表,它们也可以工作。这也有效:
print genappend('5', set('1234'))
答案 7 :(得分:0)
我同意这一点是item
是否可以迭代。
所以我的解决方案就是这样:
def iterate(seq, item):
for i in seq:
yield i
yield item
def insert_at_end(seq, item):
if hasattr(item, '__iter__'):
return seq + item
else:
return type(seq)(iterate(seq, item))
示例:
>>> insert_at_end('abc', 'x')
'abcx'
>>> insert_at_end([1, 2, 4, 6], 5)
[1, 2, 4, 6, 5]
>>> insert_at_end((1, 2, 4, 6), 5)
(1, 2, 4, 6, 5)
由于insert_at_end
可以处理iterable而不是,因此即使使用:
>>> insert_at_end('abc', 'xyz')
'abcxyz'
>>> insert_at_end([1, 2, 4, 6], [5, 7])
[1, 2, 4, 6, 5, 7]
>>> insert_at_end((1, 2, 4, 6), (5, 7))
(1, 2, 4, 6, 5, 7)
答案 8 :(得分:-1)
虽然封装依赖于类型,但是直接在insert_at_end中的代码却没有,并依赖于所有3种类型的+含义相关的东西,因此从这个意义上讲,它符合提示。