首页 > 解决方案 > 将一个元素转换为一个元素的元组/列表/集合/字符串的简洁通用方法

问题描述

我遇到一个面试问题来实现以下功能:

def f(sequence_type, element):
    pass

例如:

f(str, 'a')  return 'a'
f(list, 'a') return ['a']
f(list, 'ab') return ['ab']
f(list, 1) return [1]
f(tuple, 1) return (1, )
f(set, 1) return {1}
f(str, 1) return '1'
f(str, [1]) return '[1]'

我想出了一个天真的方法:

def f(sequence_type, element):
    return sequence_type(element)

此方法适用于str. 但是,我会得到错误,因为tupe(1)会 raise TypeError: 'int' object is not iterable

当然,我可以写一堆if else检查类型并使用特定的方式来生成一个元素序列,例如[x] (x,)等等。有没有干净和通用的方法来做到这一点?

标签: pythonpython-3.xlistsettuples

解决方案


You can approximate the requirement this way:

from collections.abc import Iterable

def f2(sequence_type, *elements):
    if isinstance(elements[0],Iterable):
        return sequence_type(elements[0])
    else:
        return sequence_type(elements[:1])

which is close, but fails for f(list, 'ab') which returns ['a', 'b'] not ['ab']

It is hard to see why one would expect a Python function to treat strings of length 2 differently from strings of length 1. The language itself says that list('ab') == ['a', 'b'].

I suspect that is an expectation imported from languages like C that treat characters and strings as different datatypes, in other words I have reservations about that aspect of the question.

But saying you don't like the spec isn't a recipe for success, so that special treatment has to be coded as such:

def f(sequence_type, elements):
    if isinstance(elements, str) and len(elements) > 1 and sequence_type != str:
        return sequence_type([elements])
    else:
        return f2(sequence_type, elements)

The result is generic but the special-casing can't really be called clean.


推荐阅读