Python 如何循环字符串列表,操作一些字符串操作并返回它们?
以下是我得出的结论:Python 如何循环字符串列表,操作一些字符串操作并返回它们?,python,regex,function,Python,Regex,Function,以下是我得出的结论: a = 'bats bear' b = 'cats pear' def sub_strings(a, b): for s in [a, b]: s = re.sub('\\b.ear\\b', '', s) return a, b a, b = sub_strings(a, b) 但这根本不起作用,函数仍然输出原始字符串('bats bear','cats pear')。这种方法有什么问题吗?试试这个 a = 'bats bear'
a = 'bats bear'
b = 'cats pear'
def sub_strings(a, b):
for s in [a, b]:
s = re.sub('\\b.ear\\b', '', s)
return a, b
a, b = sub_strings(a, b)
但这根本不起作用,函数仍然输出原始字符串('bats bear','cats pear')
。这种方法有什么问题吗?试试这个
a = 'bats bear'
b = 'cats pear'
def sub_strings(a, b):
result = []
for s in [a, b]:
result.append(re.sub('\\b.ear\\b', '', s) )
return result[0], result[1]
a, b = sub_strings(a, b)
不会做你认为它会做的事。它只是将名为s
的变量重新绑定到re.sub()
返回的修改后的字符串。它不会改变变量a
或b
。您可以通过在循环中打印出s
的值来检查这一点
相反,您可以返回一个生成器:
def sub_strings(a, b):
return (re.sub(r'\b.ear\b', '', s) for s in (a, b))
列表理解也会起作用:
def sub_strings(a, b):
return [re.sub(r'\b.ear\b', '', s) for s in (a, b)]
无论哪种方式,结果都将根据需要解压到变量a
和b
中
您可能想考虑函数的泛化,以便它接受任意数量的参数:
def sub_strings(*args):
return (re.sub(r'\b.ear\b', '', s) for s in args)
现在,您可以使用任意数量的参数调用它:
>>> print(list(sub_strings('bats bear', 'cats pear', 'rats hear')))
['bats ', 'cats ', 'rats ']
>>> print(list(sub_strings('bats bear', 'cats pear', 'rats hear', 'gnats rear')))
['bats ', 'cats ', 'rats ', 'gnats ']
您遇到的问题是,在Python中,字符串(即
str
type对象)是不可变的对象。由于无法更改字符串对象,因此对字符串执行的任何函数都不会更改原始字符串。它始终保持不变:
>>> s = 'abc'
>>> s.replace('abc', 'def') # perform some method on s
>>> print(s) # has s been changed?
abc # NOPE
如果您想获得字符串的操纵版本,您必须将操纵版本保存在某个地方并返回该版本。提供的其他答案清楚地说明了如何做到这一点
至于你的实际问题,我建议使用发电机。生成器是一种行为与普通函数非常不同的函数。其中一个区别是生成器函数能够生成多个结果—一次一个—只需一个函数调用
要制作生成器,请使用yield
,而不是使用单词return
。以下是一个例子:
a = 'bats bear'
b = 'cats pear'
def sub_string_gen(*strings):
for s in strings:
yield re.sub('\\b.ear\\b', '', s)
a, b = sub_strings(a, b) # generator is "unpacked" here
请注意,*strings
语法允许函数接受多个参数。这些参数在函数中的一个列表下可用,该列表的名称为strings
上面代码工作的原因是最后一行自动神奇地执行已执行生成器的解包。换句话说,每个结果一次生成一个,并一次一个地解压成相应的提供名称
但是,请注意不要尝试这样做:
a = sub_strings(a) # BAD!
这不会按您期望的方式工作。它将不工作,因为a=sub_strings(a)
没有打开发电机的包装;而是创建一个生成器并将其分配给a
;发电机还没有打开包装。术语说明:子字符串
是一个生成器函数<代码>子字符串(a、b、c)使用该生成器函数创建一个生成器
要将生成器解包为单个名称,请执行以下操作:
a, = sub_strings(a) # Note the comma
额外的逗号使a
成为一个符号元组,而不是一个单元组。这让解释器知道您的意思是将生成器“解包”成一个符号,a
我非常喜欢这种语法,因为它可以防止您犯不容易看到的错误。例如,如果为sub_strings
提供的参数太多,但变量不够,则会出现错误,并让您知道存在问题:
>>> a, b = sub_strings(a, b, c) # extra c argument
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
还有另一种非常好的替代语法,可以做同样的事情。在这里,我们又看到了那颗星(有些人称之为“splat”)。splat一次“解包”生成器一个值,与之前自动解包的情况大致相同:
>>> results = [*sub_strings(a, b, c, d, e, f)]
最后:你甚至不需要定义一个函数来生成一个生成器。你可以只使用所谓的a
您可以在上面我们使用生成器的任何地方使用这样的表达式:
>>> results = list((re.sub('\\b.ear\\b', '', s) for s in (a, b)))
>>> results = [*(re.sub('\\b.ear\\b', '', s) for s in (a, b))]
请注意,在以前版本的代码中,被称为生成器表达式的部分已替换为创建生成器的生成器函数调用
但是,如果您的目标是列表,则更短的语法就是使用所谓的列表理解:
>>> results = [re.sub('\\b.ear\\b', '', s) for s in (a, b)]
关于Python生成器,还有很多很多需要学习的地方。去开始吧
>>> a, b = (re.sub('\\b.ear\\b', '', s) for s in (a, b))
>>> results = list((re.sub('\\b.ear\\b', '', s) for s in (a, b)))
>>> results = [*(re.sub('\\b.ear\\b', '', s) for s in (a, b))]
>>> results = [re.sub('\\b.ear\\b', '', s) for s in (a, b)]