Python中的类型推导[重复]
Posted
技术标签:
【中文标题】Python中的类型推导[重复]【英文标题】:Type deduction in Python [duplicate] 【发布时间】:2018-03-14 06:16:38 【问题描述】:在 Python 中有没有更好的方法来确定函数参数是单个数字还是数字列表。目前我正在对通道控制流使用异常的副作用,但它看起来并不优雅:
def buildPattern( NumberOrList, Framework ):
FinalPattern = '-->'
try:
ListLen = len(NumberOrList)
#if this is a list, program flow will reach this point
I = 0
for Char in Framework:
if Char == 'x':
FinalPattern = FinalPattern + ' ' + str(NumberOrList[I])
I = (I+1) % ListLen
else:
FinalPattern = FinalPattern + ' '
except:
#if we reach this point, we don't have a list... (or some other problem)
for Char in Framework:
if Char == 'x':
FinalPattern = FinalPattern + ' ' + str(NumberOrList)
else:
FinalPattern = FinalPattern + ' '
return FinalPattern
print buildPattern( 3,'x x x x x x x x ' ) #single number call
print buildPattern( [1,3,5], 'x x x x x x x x ' ) #list call
【问题讨论】:
如果它是一个单一的 int 就把它放在一个列表中:if type(NumberOrList) == 'int': NumberOrList = [NumberOrList]
@jordanm 你写的不是pythonic,甚至不会像你写的那样工作。
【参考方案1】:
您可以使用异常处理来执行此操作,但正如您所说,它不是很优雅。此外,如果经常引发异常,效率也不高,使用显式测试会更快。
实际上,重新设计代码会更加优雅。 ;) 仅仅因为 Python 允许您定义一个函数,其中 arg 可以是数字或列表,但这并不意味着它是一个好主意。正如您所发现的那样,它往往会使函数的内部逻辑更加复杂,并且经常导致在不同的执行路径中出现重复的代码。不过不管怎样……
测试 arg 的简洁方法是查看它是否是可迭代的,您可以使用 collections.Iterable
类来执行此操作。在 Python 的现代版本中,该类已移至 collections.abc
模块,但目前仍可在 collections
中使用,以便更轻松地编写在 Python 2 和 Python 3 上正确运行的代码。
顺便说一句,使用“裸”except
通常不是一个好主意。您应该始终命名您想要捕获的异常,否则您最终可能会捕获到您不期望的东西,并且您的代码将无法正确处理。
另外,关注PEP-0008 style guide 也是一个好主意。它使其他人更容易阅读您的代码。
这是您的函数的更紧凑版本,使用 PEP-0008 样式名称编写。它使用itertools.cycle
来简化源数据的循环。它还将输出字符串收集到一个列表中,并在一个步骤中将它们连接在一起。这比在循环中进行字符串连接更有效。此代码在 Python 2 和 Python 3 上都能正常运行。
from __future__ import print_function
from collections import Iterable
from itertools import cycle
def build_pattern(source, framework):
if not isinstance(source, Iterable):
source = [source]
source = cycle(map(str, source))
final_pattern = ['-->']
for char in framework:
final_pattern.append(next(source) if char == 'x' else ' ')
return ' '.join(final_pattern)
print(build_pattern(3, 'x x x x x x x x ')) #single number call
print(build_pattern([1, 3, 5], 'x x x x x x x x ')) #list call
print(build_pattern('abcde', 'x x x x x x x x ')) #string call
输出
--> 3 3 3 3 3 3 3 3
--> 1 3 5 1 3 5 1 3
--> a b c d e a b c
正如 VPfB 在 cmets 中提到的,字符串是可迭代的,因此如果您将字符串传递给我的 build_pattern
,它将直接传递给 cycle(map(str, source))
,它不会被包装在列表中。这在这里很好,但是在某些情况下这种行为可能会导致问题,典型的情况是任意嵌套列表的展平。答案here 显示了如何处理这种情况。
【讨论】:
每个使用isinstance(arg, Iterable)
的人都应该注意一个问题。它适用于数字和许多其他类型,但不适用于字符串。单个字符串是可迭代的!这是为了支持“不是一个好主意”的观点。
@VPfB 好点,我想我应该在回答中提到这一点。但是,在这种特殊情况下,这并不重要,因为如果我们将字符串传递给 build_pattern
,它仍然会做正确的事情,正如我的代码中的最后一行所展示的那样。【参考方案2】:
你为什么不试试这个
def buildPattern(NumberOrList, Framework):
if isinstance(NumberOrList, list):
# This is list
else:
# This is number
这是 pep-8 python 风格指南推荐的,而不是 type(obj)
参考:
https://www.python.org/dev/peps/pep-0008/#programming-recommendations
【讨论】:
【参考方案3】:只需在函数顶部使用带有 isinstance 的 if 语句:
if isinstance(NumberOrList, int):
# Its a number
elif isinstance(NumberOrList,list):
# Its a list
else:
# Its something you dont want
【讨论】:
以上是关于Python中的类型推导[重复]的主要内容,如果未能解决你的问题,请参考以下文章