gpt4 book ai didi

python - 在迭代过程中与字符串中的列表/元组不同

转载 作者:行者123 更新时间:2023-12-03 19:30:15 32 4
gpt4 key购买 nike

是编写接受参数的函数的常见模式,如果参数是数字或字符串等标量,则对其应用一些操作,如果参数是可迭代的,则对每个元素应用相同的操作这个可迭代的

问题是字符串是可迭代的,所以我不能依靠请求宽恕而不是获得许可来实现这一点,因为 iter('hello world')不会引发 TypeError。

例如

def apply_(func, val):
try:
for v in iter(val):
print(func(v), end=' ')
print()
except TypeError:
print(func(val))


apply_(lambda x: x+1, 1) # 2 ... Ok
apply_(lambda x: x*2, range(3)) # 0 2 4 ... Ok
apply_(str.upper, ['hello', 'world']) # HELLO WORLD ... Okay
apply_(str.upper, 'hello world') # H E L L O W O R L D, ... oops

我可以请求许可。但这仅适用于字符串的子类型。

def apply_safe(func, val):
if issubclass(type(val), str):
print(func(val))
return

try:
for v in iter(val):
print(func(v), end=' ')
print()
except TypeError:
print(func(val))

另一种选择是将此逻辑添加到类型中,这似乎是这样做的正确方法,因为可迭代是不希望的(在这种情况下)字符串的行为。但这对调用者来说很容易出错,迟早它会忘记用 NonIterableString 调用它。或任何其他类。

class NonIterableString(str):
def __iter__(self):
raise TypeError()

apply(str.upper, NonIterableString('hello world')) # HELLO WORLD

我找到的最后一个解决方案是解决我的问题但可能不适用于现有代码的是这个

def apply_multi(func, *vals):
for v in vals:
print(func(v), end=' ')
print()

这似乎是更惯用的一种。它总是有效,小巧而优雅,但因为它不面对问题,所以巧妙地规避了它。这里的问题是我需要为每个案例编写一个这样的函数,这似乎不是一个坏主意,但仍然很冗长......

最后这里是完整的例子

def apply_(func, val):
try:
for v in iter(val):
print(func(v), end=' ')
print()
except TypeError:
print(func(val))

def apply_safe(func, val):
if (issubclass(type(val), str)):
print(func(val))
return

try:
for v in iter(val):
print(func(v), end=' ')
print()
except TypeError:
print(func(val))

def apply_multi(func, *vals):
for v in vals:
print(func(v), end=' ')
print()

class NonIterableString(str):
def __iter__(self):
raise TypeError()

apply_(lambda x: x+1, 1) # 2 => ok
apply_(lambda x: x*2, range(3)) # 0 2 4 => ok
apply_(str.upper, ['hello', 'world']) # HELLO WORLD => ok
apply_(str.upper, 'hello world') # H E L L O W O R L D => oops
apply_(str.upper, NonIterableString('hello world')) # HELLO WORLD => ok
apply_safe(str.upper, 'Hello world') # HELLO WORLD =>j
apply_multi(str.upper, 'hello world') # HELLO WORLD => ok

最后我的问题是,是否有任何 AFFNFP 方式在 python 中处理字符串,如标量类型而不是可迭代类型?

最佳答案

我认为一个好的解决方案是这样的:

defaults = {
str : False
}

def apply_(func, val, isiter: bool=None):
if isiter is None:
isiter = defaults[type(val)] if type(val) in defaults else True

if isiter:
try:
for i in iter(val):
print(func(i), end=' ')
print()
except TypeError:
print(func(val))
else:
print(func(val))
这种方法让您决定(仅当值是可迭代的)是否要将值视为可迭代的。潜在地,如果您想要字符串类型的这种行为,也许有一天您会将函数应用于列表,但仅应用于列表本身,而不是将函数应用于每个值。
这里 defaults表示默认情况下是否应将可迭代类型视为可迭代,在这种情况下 str默认情况下不应将其视为可迭代的。
如果需要,您还有一个参数可以覆盖此“默认”行为(但前提是它有意义)。例如:
apply_(lambda x: x+1, 1) # 2 ...  Ok
apply_(lambda x: x*2, range(3)) # 0 2 4 ... Ok
apply_(str.upper, ['hello', 'world']) # HELLO WORLD ... Okay
到这里一切都一样,都按预期运行。然后让我们看看:
apply_(str.upper, 'hello world') # HELLO WORLD ... Okay
apply_(str.upper, 'hello world', isiter=True) # H E L L O W O R L D ... okay
如您所见 hello world起初被视为一个值,就像我们在 defaults 中定义的那样如果我们设置 isiter=True然后按照您的设置进行处理。
让我们看另一个例子:
apply_(lambda x: 2*x, ['hello', 'world']) # hellohello worldworld ... Okay
apply_(lambda x: 2*x, ['hello', 'world'], isiter=False) # ['hello', 'world', 'hello', 'world'] ... Okay
正如您在第一种情况下看到的,列表被视为可迭代的,如果我们设置 isiter=False该函数应用于列表本身。
最后让我们看看我们是否尝试将不可迭代类型视为可迭代:
apply_(lambda x: x+1, 1, isiter=True) # 2 ...  Ok
在这种情况下, try: except:处理错误。
这本字典非常方便,因为设置默认行为将确保您必须使用 isiter大部分的时间。

关于python - 在迭代过程中与字符串中的列表/元组不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55562077/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com