0

I have the following code and for the sake of learning would like to see a more pythonic way of achieving this:

for value in response.values():
    for encod in encodings:
        if encod.lower() in value.lower():
            return(encod)

5 Answers 5

10

Assuming that you actually intend to return only the first match you find (which is what your code does), there's nothing unpythonic about your code except the unnecessary parentheses in the last line, which you can replace with:

            return encod

Pythonic does not mean 'write a one-liner' or 'use a particular feature of Python for the sake of it'. It means, among other things, 'write your code in the most easily-understood and expressive way that you can'.

See also: the Zen of Python

Sign up to request clarification or add additional context in comments.

3 Comments

If you didn't see it, here it is again: 'for the sake of learning'. I agree with you, but would like to learn how to achieve this if in other ways.
@user1991424 I did see it, yes. I also saw that you asked for 'a more pythonic way' of writing your code. Part of learning that is learning what the word pythonic means.
@user1991424: you also said you'd "like to see a more pythonic way of achieving this". That's very different from "in other ways", if the other ways are less Pythonic.
4

If you're looking for a different way, you can use this:

return next(encod for value in response.values() 
                      for encod in encodings 
                          if encod.lower() in value.lower())

The portion within next(...) is a generator expression that yields each encod in encodings for each value in response.values() if the condition encod.lower() in value.lower() is satisfied. The first element of this generator is what we return (see next()).

Although, in practice, I would generally go with what you already have. It's the simplest and clearest way to do what you are trying to do, and is by no means unpythonic.

8 Comments

NameError: global name 'encod' is not defined
I think you reversed the order of the loops, which should be fine since we only want the first one, but it's worth clarifying because the syntax of the double comprehensions is so confusing.
@user1991424 Are you sure that's happening on the return line?
ahhhh, thank you. I have been trying to learn when/how to use the next() function. Thank you! +1 for not scolding me and teaching me.
-1 This is hardly more idiomatic - it has no benefits in terms of readability or efficiency.
|
1

Your code will only return the first matching instance, but you could still use a list comprehension or better, a generator expression.

return next(v for v in response.values() if v.lower in map(lower, encodings))

1 Comment

getting AttributeError: 'generator' object has no attribute 'next'
0

Are you OK with outputting it as a list? A list comprehension would make it more Pythonic.

return [encod for value in response.values() for encod in encodings if encod.lower() in value.lower()]

3 Comments

It would have to be a str, I could use loop through the list after returning it but ideally, just astring
What exactly do you mean @user1991424? This would add each encod that matches your criteria to a list that you could then .join() if you'd like?
In my response.values(), I know that there can only be at most one encod to be matched in encodings. I would need to only return the first match.
0

Just to offer another approach using a Cartesian product. I like this because it matches the way I would think: "check every pair of values."

    import itertools
    for (encoding, value) in itertools.product(encodings, response.values()):
        if encoding.lower() in value.lower():
            return encoding

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.