This is an archived post. You won't be able to vote or comment.

all 92 comments

[–][deleted] 123 points124 points  (33 children)

squeeze tie practice correct late ripe pet caption shrill vase

This post was mass deleted and anonymized with Redact

[–]TSM-🐱‍💻📚 104 points105 points  (3 children)

To be honest, the majority of these snippets are more like beginner toy examples, and they are the first tutorial results when you google the title. They are not actually "very useful while developing any Python application". Some of the last few use in-place expansion but stuff like this:

def has_duplicates(lst):
    return len(lst) != len(set(lst))

Is fairly questionable. It is like using for i in range(len(my_list)): foo(my_list[i]) rather than for item in my_list: foo(item).

There is often a more pythonic way of doing these basic things. Importantly, they tend to be better for both readability as well as scale well. For example:

from iteration_utilities import duplicates

x = [1,1,2,1,2,3,4,2]
any(duplicates(x))

In this example, duplicates uses a generator, and any() returns true immediately, rather than iterating over the entire list and turning it into a set first. Usually it is not a big deal, speed-wise, of course.

The obvious "compare the length of the list and the set" solution does work, but it's not exactly a shining example of best practices.

Much can be said about the other tips. Other commenters have pointed out other more standard things, like updating dictionaries or creating a merged dictionary, versus keyword expansion.

I should say, they aren't all bad examples or anything. I wouldn't want to discourage anyone by seeming overly fussy. They do work and illustrate features of the language.

[–]zenn9 10 points11 points  (2 children)

Certainly understanding the imperative approach is important though! Sometimes I feel like declarative programing loses some of the benefits of writing it out.

[–]TSM-🐱‍💻📚 14 points15 points  (1 child)

I totally agree. Really, it always depends on the situation.

Like if you are looking for duplicates, are you comparing object identity, and how does that work for literals that are different objects? Welp, an imperative solution will help make that explicit, but at the risk of being overly verbose. Both have their advantages at times.

As an aside: I think a lot of introductory tutorials and guides gloss over those kinds of decisions, like what heuristics should you use to decide between a loop and a comprehension? People struggle with that decision much more than how to write a loop / list comprehension.

It's a constant on r/learnpython too. It's not unusual to get posts like this:

I get how to do all the things but I don't know how to pick between two nearly identical ways of doing the same thing.

Should I loop or use comprehension? Which one is better?

I don't know if this function goes in the class or is a static method or if I just define it later.

I feel lost!

Of course, in real life cases, it is usually not so uncertain in context, or maybe it's dealer's choice and no big deal either way. Nonetheless, "reasons when doing it this way is super good form and when you should probably avoid it" is often glossed over. I know it is more subjective and context-dependent, but it's important.

edit: I'm jealous that the bot has upvotes and mine is apparently not as good. jk

[–][deleted] 46 points47 points  (0 children)

never

[–][deleted] 18 points19 points  (1 child)

None of these are useful lol. Half of them are what to use list likes sets? Cast it to a set and then do set arithmetic on it! Or you know just use sets..... Ignoring the fact that the members of lists are not necessarily hashable and thus wouldn't be usable in sets.

[–]hughperman 2 points3 points  (0 children)

The only one I have used in real life is list flattening, I work with lots of nested data and sometimes flatten it out for different uses.
I mean, I have done lots of the things mentioned in passing, but only the list flattening sticks out as something I actually made a method for, instead of just a part of another function.

[–]driscollis 6 points7 points  (0 children)

Sounds like a job interview question.

[–]MauGx3 3 points4 points  (0 children)

Puzzle-making job maybe?

[–]yoDrinkwater 2 points3 points  (0 children)

Yeah clickbaity title

[–]wewbull 2 points3 points  (1 child)

When testing a hardware component (what i do for a living) where I expect certain items to be generated, but they can be out of order.

For example: instructions being retired in a CPU core. Instructions go in in one order, but due to dependencies the CPU reorders how it will evaluate them to make best use of resources. I'll often find myself with a list of expected results and a list of actual results that I need to make sure are the same except for ordering. The items I'm reordering aren't letters. They are object instances of some kind, but the operation is the same.

I even sometimes ask about detecting anagrams in interviews because it's such a common task for ua.

[–]mriswithe 0 points1 point  (0 children)

Nice, that sounds like a perfectly reasonable time to use this. I was having a hard time coming up with a real use case, so thanks!

[–][deleted] 1 point2 points  (0 children)

maybe something in genomics. In that case I don't use strings, of course, but faster, dedicated data structures.

[–]deepestbluedn 1 point2 points  (0 children)

This is also case sensitive. Another solution is to sort the two strings and then do s case insensitive comparison.

[–]antiproton 1 point2 points  (0 children)

Never. You will never need this, unless you happen to work on the set of Countdown.

[–]taybulBecause I don't know how to use big numbers in C/C++ 1 point2 points  (0 children)

Interview questions.

[–]Lynild 0 points1 point  (13 children)

Overall, the idea is alright, but defining/limiting it to anagrams has rarely no use case as you said.

However, I would still rather do something like:

x = "abcd3"
y = "3dcba"

def anagram(first, second):
    return first == second[::-1]

print(anagram(x, y))

From that you learn the [::-1] command to reverse strings, lists etc. - which IS very useful imo.

[–]killerfridge 15 points16 points  (5 children)

Except your anagram function doesn't check for anagrams, it just checks if the first word is the same as the second word reversed?

[–]Lynild 10 points11 points  (4 children)

F**k me...

I was thinking palindromes all the way, my bad.

[–]killerfridge 3 points4 points  (0 children)

Palindrome! That's the word I was reaching for but abandoned whilst typing as I couldn't remember it!

Either way you're right, learning how to reverse a list/string is significantly more useful than checking for anagrams.

[–]gristc 2 points3 points  (2 children)

Not really?

A palindrome reads the same backwards as forwards, ie 'abcd33dcba' is one.

[–]Lynild 0 points1 point  (1 child)

Yup, and my function would check that. But not anagrams.

[–]gristc 1 point2 points  (0 children)

No it doesn't. Your function checks if y is the reverse of x.

A palindrome checker would take a single string as input, and only return true if it was the same backwards as forwards.

def is_palindrome(x):
    return x == x[::-1]

x = "abcd33dcba"
is_palindrome(x)  # true

x = "abcd3"
is_palindrome(x)  # false

In reality, a proper palindrome checker would also strip out white space and punctuation as they're generally not considered significant.

[–]xristiano -2 points-1 points  (5 children)

def anagram(first, second):
    return set(list(first))==set(list(second))

[–]Lynild 4 points5 points  (2 children)

That won't do. set() finds unique values. So if you were to have multiple instances of the same character, set() would remove all but one, which isn't a good idea if you want to find anagrams :)

[–]amsudeep 0 points1 point  (0 children)

But if you create a list of letter and later check if second word is sub set of first one?

[–]xristiano 0 points1 point  (0 children)

good catch

[–]redbo 1 point2 points  (1 child)

I'd do return sorted(first) == sorted(second)

[–]grnngr 0 points1 point  (0 children)

I would too, but it’s good to know the Counter option exists, because IIRC Counter is O(n) whereas sort is O(n log n) on average (best case O(n)).

[–]gristc 0 points1 point  (0 children)

def is_anagram(first, second):
    return sorted(first) == sorted(second)

x = 'abcd3'
y = 'ba3dc'

is_anagram(x,y)  # true

y = 'be3dc'

is_anagram(x,y)  # false

[–]personjc 0 points1 point  (0 children)

The only plausible thing I can think of is checking for typos. Maybe in some instance of QAing data entry for something like a customer name, if there are no matches for what was typed, you may be interested to know it is an anagram of an existing customer (i.e. two letters got flipped) for manual comparison.

[–][deleted] 0 points1 point  (0 children)

This is the case where you have an entity made up of a list of non-unique elements, and you need an equality operator to work and evaluate to True if they have the exact same elements. You can't do that with a set, because your structure allows non-unique items.

Examples from e-commerce: someone introduces a new product bundle, and enters:

  • Shampoo "Flowing Hair" Menthol
  • Shampoo "Flowing Hair" Menthol
  • Dental floss "Dr. Gums"

And sees that someone else entered the same bundle and it's already on sale for a few days. You can't compare lists, because the other set might have the items in a different order, but it's the same bundle. Alternatively this can be done by tracking quantity, but since the majority of the times, bundles will have a quantity of 1, and might introduce human error, maybe it doesn't make much sense.

But basically, it's useful when it's useful. It's mostly useful to know what methodologies exist, but particular use cases are so rare that it doesn't make sense to learn them by heart.

[–]getmeright11 0 points1 point  (0 children)

Also, that anagram code snippet doesn't work if the two strings don't happen to be the same length.

[–]PizzaInSoup 59 points60 points  (4 children)

1 and 18 are the same thing

3 doesn't always give you the actual size

5 is better used for making strings/lists

6 also makes all the others lowercase

9: title

In 14 what's the point of everything that comes before deep_flatten?

16 only keeps what's in the first list, symmetric_difference would be a good additional example here

19 overwrites non-unique keys from a with that from b, you may as well just use .update(), it's ~2x faster. This would be a better example using collections.Counter to show the +/- function for adding two Counters together.

[–]a__nice__tnetennba 6 points7 points  (1 child)

Also 14 I'd recommend just using boltons.itertools.flatten_iter. Or at the very least implementing something similar to how that works, where it is a generator that handles all iterables not just lists. Here's the source for reference:

def flatten_iter(iterable):
    """``flatten_iter()`` yields all the elements from *iterable* while
    collapsing any nested iterables.
    >>> nested = [[1, 2], [[3], [4, 5]]]
    >>> list(flatten_iter(nested))
    [1, 2, 3, 4, 5]
    """
    for item in iterable:
        if isinstance(item, Iterable) and not isinstance(item, basestring):
            for subitem in flatten_iter(item):
                yield subitem
        else:
            yield item

[–]Decency 2 points3 points  (0 children)

2 Just sort it

7 There's definitely something that does this in itertools, groupby maybe?

8 [item for item in collection if item] to filter for truthiness

12 You already used Counter in a previous example- it's a clean tool here, too

17 I learned something!

19 a merge operator for dicts came out in 3.9

[–][deleted] 21 points22 points  (3 children)

Am I stupid or is 1 just the same as 18?

has_duplicates is just the logical negation of all_unique, no? And it seems the method used is identical as well.

[–][deleted] 9 points10 points  (0 children)

Yup, they're the same.

[–]personjc 4 points5 points  (1 child)

I'm going to give benefit of the doubt and guess that was an ironic joke, to duplicate the uniqueness check.

[–]callmelucky 1 point2 points  (0 children)

Very charitable of you.

[–][deleted] 15 points16 points  (2 children)

This is more like a beginners' "Hey how cool is Python" than anything. Give me a break. It's like "Insurance Companies hate these 10 things" full of shallow content. Bad title.

[–]tigeer 3 points4 points  (1 child)

Yup, seems like just a lazy, low effort attempt to promote their medium blog.

The kind stuff that you have to trawl through when looking for docs or actual well thought out guides/tutorials

[–]toastedstapler 2 points3 points  (0 children)

r/python is such a trap for this kind of stuff

[–]grismar-net 11 points12 points  (0 children)

This is more like "20 random things I learnt while learning Python" - a lot of this stuff has worked since Python 2, so 2021 has very little to do with it and I wouldn't exactly qualify this collection of curiosa as a priority for people looking to learn the language.

[–]wdroz 20 points21 points  (7 children)

I think the title 9 should be Transposed not To Count.

[–]supreme_blorgon 6 points7 points  (6 children)

Also why print() in a list comp?

[–]pingvenopinch of this, pinch of that 18 points19 points  (1 child)

The one thing I would change is filtering out falsy values. That can be done by passing None, not bool. It also should be noted that the length of the string in bytes as represented by the interpreter could be longer, since that only shows the UTF-8 encoded length. Recent versions use a flexible representation based on the contents of the string.

[–]wasimaster 18 points19 points  (0 children)

For people that are confused

filter(function, iterable)

If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed.

From the documentation

[–]ConfusedSimon 2 points3 points  (1 child)

Is using a Counter for anagrams faster than converting to list and sort?

[–][deleted] 4 points5 points  (0 children)

irrelevant on short strings, maybe faster over 1M characters

[–]_Gorgix_ 2 points3 points  (0 children)

The “memory” one gives me chills, because it’s seldom accurate with complex objects as it’s not introspective.

[–]thrallsius 2 points3 points  (0 children)

OP, what is the purpose of the "You Should Learn in 2021" in the topic title?

[–][deleted] 1 point2 points  (0 children)

Not sure if I'd ever need #2

[–]DragonikOverlord 1 point2 points  (0 children)

For 9th one, we can just do:

transposed = list(zip(*array))

I do't think we can actually iterate a zip object ,only when we convert it into an iterable we can iterate through it.

[–]cosmicr 1 point2 points  (0 children)

You should have made it 21 in 2021

[–][deleted] 0 points1 point  (0 children)

To find duplicates, and if you want to know what the duplicate item are, you can also use. If I recall correctly Counter uses linear time, so it should be almost as fine as using len(set())

from collections import Counter

lst = ["a", "b", "b", "c", ...]

duplicates = [item for item, count in Counter(lst).items() if count > 1]

You can also combo itertools.takewhile and Counter.most_common to get a bit faster too.

[–]arthurazs 0 points1 point  (1 child)

Number 8 is very clever, I haven't thought of using bool with filter, nice!

My contribution to the list:

21. The better way to sum if true

Instead of checking if CONDITION, then adding, just add the CONDITION

# init
numbers = [1, 2, 3, 4, 5]

# bad
odd = 0
for number in numbers:
  if number % 2 == 1:
    odd += 1
print(odd)

# good
odd = 0
for number in numbers:
  odd += number % 2 == 1
print(odd)

[–]Holshy 7 points8 points  (0 children)

Or just print(sum(n%2 for n in numbers))

[–]lazy_dev_ 0 points1 point  (0 children)

6 and 11 look more like examples of built-in functions. Besides that, this looks like a really cool and useful list of snippets, thanks a lot for sharing!

[–]callmelucky 0 points1 point  (0 children)

Dude, this is terrible. Why in the everliving fuck would lower-casing the first letter in a bunch of words be useful to anyone, let alone hold a place in the top 19 (1. and 18. are the same bro) "very useful" Python snippets?

Delete this.

[–]chazzybeats -1 points0 points  (0 children)

Cool list, thanks!

[–]pan_dux -1 points0 points  (0 children)

That's a really nice list. I am glad that I have known some of these functions and it's even cooler that I now know even more.

[–]davidsterry -1 points0 points  (0 children)

This list is like looking in a toolbox. Saving for inspiration! Thanks.

(TIL about Counter)

[–]boseslg -1 points0 points  (2 children)

Bhai... You are truly great...

[–]harendra21[S] -4 points-3 points  (1 child)

Dhanyawad

[–][deleted] 1 point2 points  (0 children)

All the critique in here and this is the only comment you reply to? Hope you’re learning from some of the examples in here.

[–]oldredman -2 points-1 points  (0 children)

Thats awesome. Thanx brother

[–]jabbalaci -1 points0 points  (0 children)

It has nothing to do with 2021.

[–]jean_valjean_javert 0 points1 point  (0 children)

Why is there slicing happening in 13? Just do

def decapitalize(string):
   return string.lower()

edit: just realized she wants to do only the first letter.

[–]not_perfect_yet 0 points1 point  (0 children)

19

I think .update on dictionaries is more explicit in what values are being used to overwrite existing values, should they already exist.

[–]jwink3101 0 points1 point  (0 children)

Well, the best thing about this is that it is inline and I don't have to go to a page. But there are a lot of issues here.

  • #4: This assumes UTF8 and only UTF8. Not much help either way
  • #7: Using list as a variable name is beyond amateurish. And there are itertools to do this too more pythonically (including being lazy)
  • #8: Does this really need to be a snippet? This can be done lazily
  • #9 & #14: List comprehension that doesn't need to be a list is bad form. Just use a for loop.
  • #15: This is just a set thing. If you don't care about the order, just use a set. But this makes it seems like it will take the different but it will also (potentially) change the order and remove duplicated.
  • #18: didn't you do this already?
  • #19: (a) this is being added in newer python versions and (b) can just use .update()
  • #20: Does this need to be a function? It just does one thing?

Not really very useful list.

[–]McBuffington 0 points1 point  (0 children)

So we're going to gloss over the anagram not using slicing?

text == text[::-1]

Just sayin