8 Python Tricks Used by Experienced Programmers

image



Here are eight graceful Python tricks that I'm sure you haven’t seen yet. Apply these tricks in your Python code to make it more concise and efficient!



1. Sorting objects by several keys



Suppose we want to sort the following list of dictionaries:



people = [
{ 'name': 'John', "age": 64 },
{ 'name': 'Janet', "age": 34 },
{ 'name': 'Ed', "age": 24 },
{ 'name': 'Sara', "age": 64 },
{ 'name': 'John', "age": 32 },
{ 'name': 'Jane', "age": 34 },
{ 'name': 'John', "age": 99 },
]


But we don't just want to sort them by name or age, we want to sort them by both fields. In SQL, this would be a query like this:



SELECT * FROM people ORDER by name, age


Actually, there is a very simple solution to this problem, thanks to Python's guarantee that the sorting functions provide sorting stability . This means that the elements that are compared keep their original order.



To achieve sorting by name and age, we can do this:



import operator
people.sort(key=operator.itemgetter('age'))
people.sort(key=operator.itemgetter('name'))


Notice how I changed the order. First we sort by age, and then by name. Using operator.itemgetter()we get the age and name fields from each dictionary in the list.



This gives us the result we wanted:



[
 {'name': 'Ed',   'age': 24},
 {'name': 'Jane', 'age': 34},
 {'name': 'Janet','age': 34},
 {'name': 'John', 'age': 32},
 {'name': 'John', 'age': 64},
 {'name': 'John', 'age': 99},
 {'name': 'Sara', 'age': 64}
]


Names are sorted first, age is sorted if name matches. Thus, all Johns are grouped by age.



The source of inspiration is a question from StackOverflow .



2. List inclusion (List Generator)



List inclusions can replace the ugly loops used to populate the list. Basic syntax for list inclusions:



[ expression for item in list if conditional ]


A very simple example for filling a list with a sequence of numbers:



mylist = [i for i in range(10)]
print(mylist)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


And since you can use an expression, you can do some math as well:



squares = [x**2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


Or even call an external function:



def some_function(a):
    return (a + 5) / 2
    
my_formula = [some_function(i) for i in range(10)]
print(my_formula)
# [2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0]


Finally, you can use "if" to filter the list. In this case, we only store those values ​​that are divisible by 2:



filtered = [i for i in range(20) if i%2==0]
print(filtered)
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]


3. Check the memory usage of your objects



Using sys.getsizeof () you can check the memory usage of an object:



import sys

mylist = range(0, 10000)
print(sys.getsizeof(mylist))
# 48


Wow ... wait ... why is this huge list weighing just 48 bytes?

This is because the range function returns a class that only behaves like a list. A range is much less memory intensive than an actual list of numbers.

You can see for yourself by using list inclusions to create an actual list of numbers from the same range:



import sys

myreallist = [x for x in range(0, 10000)]
print(sys.getsizeof(myreallist))
# 87632


So, after playing with sys.getsizeof(), you can learn more about Python and your memory usage.



4. Data classes



Since version 3.7, Python offers data classes. There are several advantages over regular classes or other alternatives, such as returning multiple values ​​or dictionaries:



  • data class requires minimal code
  • you can compare data classes because there is __eq__
  • you can easily infer the data class for debugging because there is __repr__
  • data classes require tape hints, which reduces the chance of errors


Here is an example of a data class in operation:



from dataclasses import dataclass

@dataclass
class Card:
    rank: str
    suit: str
    
card = Card("Q", "hearts")

print(card == card)
# True

print(card.rank)
# 'Q'

print(card)
Card(rank='Q', suit='hearts')


A detailed guide can be found here .



5. The attrs package



Instead of data classes, you can use attrs . There are two reasons to choose attrs:



  • You are using a Python version older than 3.7
  • You want more features


The package attrssupports all major Python versions including CPython 2.7 and PyPy. Some of the additional attributes offered attrsover regular data classes are validators and converters. Let's take a look at some example code:



@attrs
class Person(object):
    name = attrib(default='John')
    surname = attrib(default='Doe')
    age = attrib(init=False)
    
p = Person()
print(p)
p = Person('Bill', 'Gates')
p.age = 60
print(p)

# Output: 
#   Person(name='John', surname='Doe', age=NOTHING)
#   Person(name='Bill', surname='Gates', age=60)


The authors attrsactually worked in the PEP that introduced the data classes. Data classes are deliberately kept simpler (easier to understand), while attrs offers a full set of features you might need!



More examples can be found on the attrs examples page .



6. Combining dictionaries (Python 3.5+)



Since Python 3.5, it is easier to combine dictionaries:



dict1 = { 'a': 1, 'b': 2 }
dict2 = { 'b': 3, 'c': 4 }
merged = { **dict1, **dict2 }
print (merged)
# {'a': 1, 'b': 3, 'c': 4}


If there are overlapping keys, the keys from the first dictionary will be overwritten.



In Python 3.9, combining dictionaries becomes even cleaner. The above merge in Python 3.9 can be rewritten as:



merged = dict1 | dict2


7. Search for the most common value



To find the most common value in a list or string:



test = [1, 2, 3, 4, 2, 2, 3, 1, 4, 4, 4]
print(max(set(test), key = test.count))
# 4


Do you understand why this works? Try to figure this out yourself before reading on.



You even tried, didn't you? I will tell you anyway:



  • max()will return the largest value in the list. The argument keytakes a single argument function to customize the sort order, in this case test.count. The function is applied to each element of the iterable.
  • test.count- built-in list function. It takes an argument and will count the number of occurrences for that argument. So it test.count(1)will return 2 and test.count(4)return 4.
  • set(test) returns all unique values ​​from test, so {1, 2, 3, 4}


So, in this single line of code, we accept all unique values ​​for a test that is {1, 2, 3, 4}. Next, it will maxapply a function to them list.countand return the maximum value.



And no - I did not invent this one-liner.



Update: A number of commentators have rightly noted that there is a much more efficient way to do this:



from collections import Counter
Counter(test).most_common(1)
# [4: 4]


8. Returning multiple values



Functions in Python can return more than one variable without a dictionary, list, or class. It works like this:



def get_user(id):
    # fetch user from database
    # ....
    return name, birthdate

name, birthdate = get_user(4)


This is normal for a limited number of return values. But everything that exceeds 3 values ​​should be placed in the (data) class.



image



Find out the details of how to get a high-profile profession from scratch or Level Up in skills and salary by taking SkillFactory's paid online courses:











All Articles