Python: Expanding the scope of the iterator variable in the any() function

陌路散爱 提交于 2020-01-03 19:43:27

问题


I wrote some structurally equivalent real world code, where I anticipated the result for firstAdjective would be quick. But the result shows that word is out of scope. What is a neat solution that will overcome this but still retain the 'linguistic' style of what I want to do?

>>> text = 'the quick brown fox jumps over the lazy dog'
>>> adjectives = ['slow', 'quick', 'brown', 'lazy']
>>> if any(word in text for word in adjectives):
...     firstAdjective = word
...     
Traceback (most recent call last):
  File "<interactive input>", line 2, in <module>
NameError: name 'word' is not defined

回答1:


You can use next on a generator expression:

firstAdjective = next((word for word in adjectives if word in text), None)

if firstAdjective:
    ... 

A default value of None is returned when the word is not found (credit @Bakuriu)

Trial:

>>> firstadjective = next((word for word in adjectives if word in text), None)
>>> firstadjective
'quick'



回答2:


Would something like

for word in filter(lambda x: x in adjectives, text.split()):
    print word

work?




回答3:


Your example does not work because the word variable only exists during the evaluation of the condition. Once it is done finding whether the condition is true or false, the variable goes out of scope and does not exist anymore.

Even declaring it first doesn't help, as it doesn't affect the existing variable:

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['slow', 'quick', 'brown', 'lazy']
word = None
if any(word in text for word in adjectives):
    print(word)

None

Therefore, you have to do it differently, using the next function:

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['slow', 'quick', 'brown', 'lazy']
word = next((word for word in adjectives if word in text), None)
if word:
    print(word)

quick

Note, perhaps word is a misleading variable name here, because it doesn't necessarily have to match a whole word. i.e.

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['slo', 'uick', 'rown', 'azy']
word = next((word for word in adjectives if word in text), None)
if word:
    print(word)

uick

so it might be best to split the text into words first:

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['slow', 'quick', 'brown', 'lazy']
word_list = text.split()
word = next((word for word in adjectives if word in word_list), None)
if word:
    print(word)

but note that if we change the adjectives order:

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['brown', 'quick', 'slow', 'lazy']
word_list = text.split()
word = next((word for word in adjectives if word in word_list), None)
if word:
    print(word)

we get:

brown

which isn't the first adjective in the text.

Therefore, we need to check in the order of the words in the text, not the order of adjectives in the list.

text = 'the quick brown fox jumps over the lazy dog'
adjectives = ['brown', 'quick', 'slow', 'lazy']
word_list = text.split() # NOTE: this "optimization" is no longer necessary now
word = next((word for word in word_list if word in adjectives), None)
if word:
    print(word)

credit to HolyDanna for spotting this




回答4:


>>> text = 'the quick brown fox jumps over the lazy dog'
>>>
>>> # 1. Case with no match among the adjectives: Result None as expected
>>> adjectives = ['slow', 'crippled']
>>> firstAdjective = next((word for word in adjectives if word in text), None)
>>> firstAdjective
>>>   
>>> # 2. Case with a match to 1st available in adjectives but actually 2nd in the text
>>> adjectives = ['slow', 'brown', 'quick', 'lazy']
>>> firstAdjective = next((word for word in adjectives if word in text), None)
>>> firstAdjective
'brown'
>>> # 3. Case with a match to 1st available in the text, which is what is wanted
>>> firstAdjective = next((word for word in text.split() if word in adjectives), None)
>>> firstAdjective
'quick'
>>> # 4. Case where .split() is omitted. NOTE: This does not work. 
>>> # In python 2.7 at least, .split() is required
>>> firstAdjective = next((word for word in text if word in adjectives), None)
>>> firstAdjective
>>> 


来源:https://stackoverflow.com/questions/38476877/python-expanding-the-scope-of-the-iterator-variable-in-the-any-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!