Generate secure, URL safe, random tokens in Python
Python tip:
Use
secrets.token_urlsafe()
to generate security tokens.For example, you can generate a token for a password reset👇
import secrets url = f"https://my-app.com/password-reset/token={secrets.token_urlsafe()}" print(url) # => https://my-app.com/password-reset/token=KzmPWanja-z0r2BpyC7mFAZd5LXvp8SnIUbSnQyEMWw
Executing modules with runpy in Python
Python tip:
You can use
runpy
to run a module without importing it first. It works the same as the-m
command line option.An example👇
######## example.py ######## print("I am an example") ######## run_example.py ######## import runpy runpy.run_module(mod_name="example") # to run module example.py # -> I am an example
FIFO and LIFO queue examples in Python
Python tip:
You can create a simple FIFO or LIFO queue with the
queue
module.An example👇
import queue my_queue = queue.Queue() my_queue.put("Jan") my_queue.put("Mike") print(my_queue.get()) # => Jan print(my_queue.get()) # => Mike my_lifo_queue = queue.LifoQueue() my_lifo_queue.put("Jan") my_lifo_queue.put("Mike") print(my_lifo_queue.get()) # => Mike print(my_lifo_queue.get()) # => Jan
Using Django's choices field option
Django tip:
Use
choices
for character fields with a finite number of possible values.For example, you can use it for blog's status:
from django.db import models class Blog(models.Model): DRAFT = "DRF" PUBLISHED = "PUB" DELETED = "DEL" STATUS_CHOICES = [ (DRAFT, "Draft"), (PUBLISHED, "Published"), (DELETED, "Deleted"), ] title = models.CharField(max_length=120) content = models.TextField() contributors = models.TextField() status = models.CharField(max_length=3, choices=STATUS_CHOICES, default="DRAFT")
Django CharField vs TextField
Django tip:
Use
models.TextField
for storing long texts inside your models instead ofmodels.CharField
sinceCharField
has a max length of 255 characters whileTextField
can hold more than 255 characters.An example:
from django.db import models class Blog(models.Model): title = models.CharField(max_length=120) content = models.TextField() contributors = models.TextField()
Django Rest Framework - read only views
Django REST Framework tip:
You can use
ReadOnlyModeViewSet
when you don't want to allow any unsafe operations (POST, DELETE, PATCH).An example👇
class BlogViewSet(ReadOnlyModeViewSet): """ A simple ViewSet for viewing blogs. """ queryset = Blog.objects.all() serializer_class = BlogSerializer
Python pprint – pretty-print data structures
Python tip:
You can use
pprint.pprint
to print a formatted representation of an object.For example:
import json import pprint from urllib.request import urlopen with urlopen("https://pypi.org/pypi/flask/json") as resp: project_info = json.load(resp)["info"] pprint.pprint(project_info) """ {'author': 'Armin Ronacher', 'author_email': '[email protected]', 'bugtrack_url': None, ... 'requires_python': '>=3.6', 'summary': 'A simple framework for building complex web applications.', 'version': '2.0.1', 'yanked': False, 'yanked_reason': None} """
Python pathlib.Path.expanduser()
Python tip:
You can use
Path.expanduser
frompathlib
to convert~
and~user
paths to the full path.Example:
import pathlib path = pathlib.Path("~/Documents/test.txt") print(path) # => ~/Documents/test.txt print(path.expanduser()) # => /Users/michael/Documents/test.txt
Check if file is a symlink in Python
Python tip:
You can use
pathlib.Path.is_symlink
to check whether the path is a symbolic link.An example👇
import pathlib path = pathlib.Path("/usr/bin/python") print(path.is_symlink()) # => True
Filename pattern matching in Python with pathlib.Path.glob()
Python tip:
You can use
pathlib.Path.glob()
to list all files matching a given pattern.For example, you can list names of all txt files located inside the same directory as your Python script👇
import pathlib parent_folder = pathlib.Path(__file__).parent.absolute() print(parent_folder) for file in parent_folder.glob("*.txt"): print(file.name) """ example.txt first.txt second.txt """
Sort a list of objects based on an attribute of the objects in Python
Python tip:
You can use
attrgetter
to sort a list of objects based on the value of the selected attribute.An Example👇
from operator import attrgetter class User: def __init__(self, username): self.username = username def __repr__(self): return f'User(username="{self.username}")' users = [User("johndoe"), User("bobby"), User("marry")] print(sorted(users, key=attrgetter("username"))) # => [User(username="bobby"), User(username="johndoe"), User(username="marry")]
Test-diven devopment and pair programming
TDD Tip:
When practicing Test-driven Development with pair programming, try having one developer write the failing test while the other writes the code to get it to pass. The first developer is the responsible for any refactoring.
Why?
- It's fun.
- This can accelerate the learning of a less experienced developer when paired with a more experienced developer.
For more TDD benefits, check out What is Test-Driven Development? .
Find the mime type of a file in Python
Python tip:
You can use
mimetypes.guess_type
to get a mime type and encoding for a file from its name.For example👇
import mimetypes mime_type, _ = mimetypes.guess_type("my _ file. pdf") print(mime_type) # => application/pdf mime_type, encoding = mimetypes.guess_type("archive. tar.gz") print(mime_type, encoding) # => application/x-tar gzip
Python - logging with filters
Python tip:
You can use
Filter
from thelogging
module to add additional information to your log records.For example, you can add the username of the system user who's running the program👇
import logging import os class UserRunningProgramFilter(logging.Filter): def filter(self, record): record.user = os.getenv("User") return True if __name__ == "__main__": levels = ( logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL, ) logging.basicConfig( level=logging.DEBUG, format="%(asctime)-15s %(name)-5s %(levelname)-8s Run by User: %(user)-20s %(message)s", ) logger = logging.getLogger("mylogger") f = UserRunningProgramFilter() logger.addFilter(f) logger.debug("A debug message") # => 2021-09-22 07:56:45,473 mylogger DEBUG Run by User: johndoe A debug message
Python For Else
Python tip:
You can use
else
withfor
loops when searching for something. Code inside theelse
will be executed if the break statement isn't hit.items = ["right_one", "my_item", " another_item"] def right_one(item_to_check): if item_to_check == "right_one": return True else: return False for item in items: if right_one(item): print("Do something with the item") break else: print("I will do something else, no item to process") """ Do something with the item """ items = ["different_item", "my_item", "another_item"] for item in items: if right_one(item): print("Do something with the item") break else: print("I will do something else, no item to process") """ I will do something else, no item to process I will do something else, no item to process I will do something else, no item to process """
Django - custom user model
Django Tip:
Use a custom user model when starting a project
When starting a new project, set up a custom user model. This model behaves just like the default user model, but you'll be able to customize it in the future.
That should be done before creating or running any migrations.
https://testdriven.io/blog/django-custom-user-model/
# users/models.py from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): pass # users/adming.py from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import CustomUser admin.site.register(CustomUser, UserAdmin) # settings.py AUTH_USER_MODEL = "users.CustomUser"
Python - prettyprint JSON with json.dumps
Python tip:
You can use the
indent
parameter withjson.dumps
to get an indented multiline string instead of a single line.It's much easier to read.
An example👇
import json users = [ {"username": "johndoe", "active": True}, {"username": "Mary", "active": False} ] print(json.dumps(users)) # [{"username": "johndoe", "active": true}, {"username": "Mary", "active": false}] print(json.dumps(users, indent=2)) """ [ { "username": "johndoe", "active": true }, { "username": "Mary", "active": false } ] """
linecache.getline() in Python
Python tip:
You can get any line from a file by using the
getline
method fromlinecache
:linecache.getline(filename, lineno, module_globals=None)
It never raises an exception. Instead, it returns
''
(no line with a number, no file, ...).The
trackback
module uses it to retrieve source lines for formatted tracebacks.An example👇
import linecache """ Content of example. txt: Example Tweet too """ print(linecache.getline("example.txt", 2)) # => Tweet
Check if a string is a valid keyword in Python
Python tip:
You can check whether some string is a reserved Python keyword with the
keyword
module.An example👇
import keyword """" False await else import pass None break except in raise True class finally is return and continue for lambda try as def from nonlocal while assert del global not with async elif if or yield """ print(keyword.iskeyword("raise")) # => True print(keyword.iskeyword("foo")) # => False
Comparing files in Python
Python tip:
You can check if two files are equal with
cmp
from thefilecmp
module. It returnsTrue
if the files are equal andFalse
if they're not.For example:
import filecmp print(filecmp.cmp("file.pdf", "file.pdf")) # => True print(filecmp.cmp("file.pdf", "file1.pdf")) # => False
Automatically setting an enum member's value in Python
Python tip:
When the exact value of an enum member is not important, you can use
auto()
to auto-generate it:The value starts at 1 and then increases incrementally by 1.
https://docs.python.org/3/library/enum.html#using-automatic-values
An example👇
from enum import Enum, auto class Status(Enum): DRAFT = auto() IN_REVIEW = auto() PUBLISHED = auto() DELETED = auto() print(list(Status)) """ [<Status.DRAFT: 1>, <Status.IN_REVIEW: 2>, <Status.PUBLISHED: 3>, <Status.DELETED: 4>] """
Python deep copy via copy.deepcopy()
You can use
copy.deepcopy()
to create a copy of a compound object.
deepcopy
creates a copy of the object and of all its nested objects. Changes to the original object won't affect the copied object since new objects are created instead of just referencing.import copy house = { "width": 12, "length": 8, "height": 3.5, "doors": [ {"type": " ENTRANCE", "width": 0.9, "height": 2.2}, {"type": "BACK DOOR", "width": 0.7, "height": 2.0}, ], } same_house = copy.deepcopy(house) print(house) print(same_house) print(house == same_house) """ {'width': 12, 'length': 8, 'height': 3.5, 'doors': [{'type': ' ENTRANCE', 'width': 0.9, 'height': 2.2}, {'type': 'BACK DOOR', 'width': 0.7, 'height': 2.0}]} {'width': 12, 'length': 8, 'height': 3.5, 'doors': [{'type': ' ENTRANCE', 'width': 0.9, 'height': 2.2}, {'type': 'BACK DOOR', 'width': 0.7, 'height': 2.0}]} True """ house["height"] = 4.0 print(house) print(same_house) print(house == same_house) """ {'width': 12, 'length': 8, 'height': 4.0, 'doors': [{'type': ' ENTRANCE', 'width': 0.9, 'height': 2.2}, {'type': 'BACK DOOR', 'width': 0.7, 'height': 2.0}]} {'width': 12, 'length': 8, 'height': 3.5, 'doors': [{'type': ' ENTRANCE', 'width': 0.9, 'height': 2.2}, {'type': 'BACK DOOR', 'width': 0.7, 'height': 2.0}]} False """
Create a CSV file from a list of dictionaries in Python
Python tip:
You can use
DictWriter
to create a CSV file from a list of dictionaries.An example👇
import csv users = [ {"username": "johndoe", "name": "John Doe"}, {"username": "bob", "name": "Bob Builder"}, {"username": "daisy", "name": "Daisy Flower"}, ] fieldnames = ["username", "name"] with open("users.csv", "w") as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(users) """ users.csv username,name johndoe,John Doe bob,Bob Builder daisy,Daisy Flower """
Python - comparing two text files with difflib.HtmlDiff()
Python tip:
You can use
HtmlDiff
to generate an HTML table that shows a side by side, line by line comparison of the text with inter-line and intra-line change highlights.https://docs.python.org/3/library/difflib.html#difflib.HtmlDiff
An example👇
import difflib from pathlib import Path first_file_lines = Path('first.txt').read_text().splitlines() second_file_lines = Path('second.txt').read_text().splitlines() html_diff = difflib.HtmlDiff().make_file(first_file_lines, second_file_lines) Path('diff.html').write_text(html_diff)
Python - find all similar strings from a provided word within a list of strings
Python tip:
You can use
get_close_matches
fromdifflib
to find all similar strings from a provided word within a list of strings:difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)
For example, find similar names👇
from difflib import get_close_matches name = "John" names = ["John", "Jane", "Bob", "Daisy", "Jim", "Mark", "Johnny", "Mike"] print(get_close_matches(name, names)) # => ['John', 'Johnny']
Python - Using SequenceMatcher.ratio() to find similarity between two strings
Python tip:
You can use
difflib.SequenceMatcher.ratio()
to get the distance between two strings:
- T - total number of elements in both strings (
len(first_string)
+len(second_string)
)- M - number of matches
Distance = 2.0 * M / T -> between 0.0 and 1.0 (1.0 if the sequences are identical, and 0.0 if they don't have anyhing in common)
https://docs.python.org/3/library/difflib.html#sequencematcher-objects
For example:
from difflib import SequenceMatcher first = "Jane" second = "John" print(SequenceMatcher(a=first, b=second).ratio()) # => 0.5
Decimal vs float in Python
Python tip:
You can use
Decimal
instead offloat
to:
- incorporate a notion of significant places (1.20 + 1.30 = 2.50)
- represent decimal numbers exactly (1.1 + 2.2 = 3.3)
In short, use
Decimal
when precision matters.An example 👇
from decimal import Decimal print(1.20 + 1.30) # => 2.5 print(Decimal("1.20") + Decimal("1.30")) # => 2.50 print(1.1 + 2.2) # => 3.3000000000000003 print(Decimal("1.1") + Decimal("2.2")) # => 3.3
RGB to HSV in Python with colorsys
Python tip:
You can use
colorsys
to convert colors between different color systems.https://docs.python.org/3/library/colorsys.html
RGB to HSV👇
import colorsys # we need values between 0 and 1, you need to divide by 255 rgb = (0.00, 0.19, 0.56) # 00308F | (0, 48, 143) -> AirForce Blue print(colorsys.rgb_to_hsv(*rgb)) # => (0.6101190476190476, 1.0, 0.56)
Python - __post_init__ method in Dataclasses
Python tip:
You can use
__post_init__
on classes decorated withdataclass
to add custom logic on init.For example, to set a value of an attribute based on a different attribute's value:
from dataclasses import dataclass, field @dataclass class Order: net: float vat: float total: float = field(init=False) def __post_init__(self): self.total = self.net + self.vat order = Order(net=100.00, vat=22.00) print(order) # => Order(net=100.0, vat=22.0, total=122.0)
Semi-immutable Python objects with frozen dataclasses
Python tip:
You can freeze instances of a class decorated with
dataclass
by settingfrozen
toTrue
.https://docs.python.org/3/library/dataclasses.html#frozen-instances
An error will be raised if you try to assign a new value to any of attributes.
For example:
from dataclasses import dataclass @dataclass(frozen=True) class Post: title: str content: str post = Post(title="Happy new year", content="2020 is finally over") post.title = "Awesome new year" """ Traceback (most recent call last): File "example.py", line 12, in <module> post.title = "Awesome new year" File "<string>", line 4, in __setattr__ dataclasses.FrozenInstanceError: cannot assign to field 'title' """
Python's monthrange() method
Python tip:
You can use
monthrange
from thecalendar
module to get the weekday of the first day in a month and the number of days in a month.An example👇
import calendar weekday, number_of_days = calendar.monthrange(2021, 2) print(calendar.day_name[weekday], number_of_days) # Monday 28
Python weekday() method from the calendar module
Python tip:
Use
weekday
from thecalendar
module to get a day in a week (0
is Monday) for a specific date.An example👇
import calendar days = { 0: "Monday", 1: "Tuesday", 2: "Wednesday", 3: "Thursday", 4: "Friday", 5: "Saturday", 6: "Saturday", } day_in_week = calendar.weekday(1975, 10, 23) print(days[day_in_week]) # Thursday
Test interactive Python examples with doctest
Python tip:
You can use the
doctest
module to run interactive code examples inside your docstrings.It notifies you If any of the examples don't return the expected value.
👇
def sum_ab(a, b): """ Sum numbers a and b >>> sum_ab(1, 3) 4 >>> sum_ab(-41, 50) 1 :return: sum of 2 numbers """ return a + b # python -m doctest example.py # ********************************************************************** # File "example.py", line 4, in example.sum_ab # Failed example: # sum_ab(-41, 50) # Expected: # 1 # :return: sum of 2 numbers # Got: # 9 # ********************************************************************** # 1 items had failures: # 1 of 2 in example.sum_ab # ***Test Failed*** 1 failures.
Python itertools.zip_longest() Example
Python tip:
You can use
zip_longest
fromitertools
to zip multiple iterables of different lengths."Missing" values from shorter iterables are replaced by
fillvalue
.An example 👇
from itertools import zip_longest students = ["Bob", "Ann", "John", "Marry", "Daisy", "Amy"] grades = ["A", "A+", "D"] for student, grade in zip_longest(students, grades, fillvalue="-"): print(student, grade)
How do I use itertools.groupby()?
Python tip:
You can use
groupby
fromitertools
to group elements.
- Returns - an iterator of consecutive keys and groups from the iterable.
- Keys - values returned from
key
function- Groups - iterator returns values for group
For example, to group tax IDs 👇
import re from itertools import groupby tax_ids = [ "DE123456789", "ATU99999999", "BG999999999", "IT12345678900", "DE987654321", ] grouped_tax_ids = groupby( tax_ids, key=lambda tax_id: re.match(r"[A-Z]{2}", tax_id).group() ) for country, country_tax_ids in grouped_tax_ids: print(country, list(country_tax_ids)) # DE ['DE123456789'] # AT ['ATU99999999'] # BG ['BG999999999'] # IT ['IT12345678900'] # DE ['DE987654321']
Python's Itertools.cycle()
Python tip:
Do you need to repeat a sequence over and over again?
Use
cycle
fromitertools
👇from itertools import cycle chord_sequence = cycle(["G", "D", "e", "C"]) song_chords = [next(chord_sequence) for _ in range(16)] print(song_chords) # ['G', 'D', 'e', 'C', 'G', 'D', 'e', 'C', 'G', 'D', 'e', 'C', 'G', 'D', 'e', 'C']
Django - Use foreign key values directly
Django tip:
Use foreign key values directly.
Make sure to use the foreign key property instead of the foreign object ID.
- DON'T:
Song.objects.get(id=1).singer.id
- DO:
Song.objects.get(id=1).singer_id
from django.db import connection, reset_queries from .models import Song reset_queries() # makes an extra SQL query to load the singer object: Song.objects.get(id=1).singer.id len(connection.queries) # => 2 reset_queries() # an extra SQL query is not required: Song.objects.get(id=1).singer_id len(connection.queries) # => 1
Python - itertools.count()
Python tip:
You can use
count
fromitertools
to make an iterator that returns evenly spaced values:itertools.count(start=0, step=1)
For example, to generate all odd numbers greater or equal to 101👇
from itertools import count odd_numbers = count(101, 2) # first ten elements for _ in range(10): print(next(odd_numbers)) """ 101 103 105 107 109 111 113 115 117 119 """
Python - itertools.combinations()
Python tip:
You can generate all combinations of elements from an iterable of length n by using
combinations
fromitertools
.For example, you can generate all possible match pairs 👇
from itertools import combinations players = ["John", "Daisy", "Marry", "Bob"] print(list(combinations(players, 2))) """ [ ('John', 'Daisy'), ('John', 'Marry'), ('John', 'Bob'), ('Daisy', 'Marry'), ('Daisy', 'Bob'), ('Marry', 'Bob'), ] """
Function overloading with singledispatchmethod from functools
Python tip (>=3.8):
You can use
singledispatchmethod
to implement different (re)actions based on the first (non-self, non-cls) function's argument type.For each type, you register an overloaded implementation.
For example, you can handle different events 👇
from functools import singledispatchmethod class Event: pass class UserSignedUp(Event): def __init__(self, email): self.email = email class CustomerCanceledSubscription(Event): def __init__(self, email): self.email = email class EventHandler: @singledispatchmethod def handle_event(event: Event): pass # do nothing @handle_event.register def _(self, event: UserSignedUp): print(f"I will prepare resources for newly signed up user: {event.email}") @handle_event.register def _(self, event: CustomerCanceledSubscription): print(f"I will disable resources for customer: {event.email}") events = [ UserSignedUp(email="[email protected]"), CustomerCanceledSubscription(email="[email protected]"), ] handler = EventHandler() for event in events: handler.handle_event(event) # I will prepare resources for newly signed up user: [email protected] # I will disable resources for customer: [email protected]
Python functools - total_ordering()
Python tip:
You can create an orderable class (assuming the type is totally ordered) with
__eq__
, one other comparison methods (__ne__
,__lt__
,__le__
,__gt__
,__ge__
), and thetotal_ordering
decorator.An example👇
from functools import total_ordering @total_ordering class Sample: def __init__(self, value): self.value = value def __lt__(self, other): return self.value < other.value x = Sample(3) y = Sample(4) for expression in ["x == y", "x != y", "x < y", "x <= y", "x > y", "x >= y"]: result = eval(expression) print(f"{expression} is {result}") """ x == y is False x != y is True x < y is True x <= y is True x > y is False x >= y is False """
Without it, you'd need to define all of the comparison methods.
Provision and manage remote Docker hosts with Docker Machine
Docker tip:
Use Docker Machine to quickly provision a remote machine for testing
https://docs.docker.com/machine/
# spin up an ec2 instance with docker engine installed $ docker-machine create \ --driver amazonec2 \ --amazonec2-open-port 8000 \ --amazonec2-region us-east-1 \ --amazonec2-instance-type "t2.micro" \ sandbox # point your docker daemon at the remote docker engine $ docker-machine env sandbox $ eval $(docker-machine env sandbox) # build the images and spin up the containers on the remote machine $ docker-compose up -d --build # ssh certs are auto generated, so you can easily ssh to the remote $ docker-machine ssh sandbox # you can also copy files to/ from the machine $ docker-machine scp docker-machine scp sandbox:~/foo.txt ~/ $ docker-machine scp docker-machine scp foo.tar.gz sandbox:/home/ubuntu
Python functools - cached_property()
Python tip (>=3.8):
You can use
cached_property
fromfunctools
to cache the results of a class attribute for the life of the instance. It's useful if you have a property that is expensive to compute and doesn't need to change.An example 👇
import io import pathlib from functools import cached_property from pikepdf import Pdf class PDF: def __init__(self, file_bytes): self.file_bytes = file_bytes @cached_property def number_of_pages(self): return len(Pdf.open(io.BytesIO(self.file_bytes)).pages) pdf = PDF(pathlib.Path("file.pdf").read_bytes()) print(pdf.number_of_pages)
What's the difference between select_related and prefetch_related in Django?
Django tip:
Select_related vs prefetch_related
- Use
select_related()
on OneToOneField or ForeignKey when you need a single object- Use
prefetch_related()
on ManyToManyFields or reverse relations when you need many objects👇
class Singer(models.Model): first_name = models.CharField(max_length=40) last_name = models.CharField(max_length=40) class Song(models.Model): name = models.CharField(max_length=100) singer = models.ForeignKey(Singer, related_name="songs") Song.objects.select_related("singer").all() # Forward ForeignKey relationship Singer.objects.select_related("song").all() # Backward ForeignKey relationship
Python - function overloading with singledispatch
Python tip:
You can use
singledispatch
to implement different (re)actions based on the first function's argument typeFor each type, you register an overloaded implementation
For example, you can handle different events like so:
from functools import singledispatch class Event: pass class UserSignedUp(Event): def __init__(self, email): self.email = email class CustomerCanceledSubscription(Event): def __init__(self, email): self.email = email @singledispatch def handle_event(event: Event): pass # do nothing @handle_event.register(UserSignedUp) def _(event: UserSignedUp): print(f"I will prepare resources for newly signed up user: {event.email}") @handle_event.register(CustomerCanceledSubscription) def _(event: CustomerCanceledSubscription): print(f"I will disable resources for customer: {event.email}") events = [ UserSignedUp(email="[email protected]"), CustomerCanceledSubscription(email="[email protected]"), ] for event in events: handle_event(event) # I will prepare resources for newly signed up user: [email protected] # I will disable resources for customer: [email protected]
Use the Django auth system with a Single Page App (SPA)
Django tip:
Coupling Django with a front-end framework like React, Vue, or Angular? Use session cookies for auth (even cross-domain).
Why?
- It's easier since Django has a powerful built-in auth system
- It's safer than using JWTs and localStorage
Caching in Python with lru_cache
Python tip:
Improve the performance of a function with the
lru_cache
decorator fromfunctools
:@functools.lru_cache(maxsize=128, typed=False)
maxsize
: max number of stored argumentstyped
: different types will be cached separately (i.e., 3 != 3.0)- function args and kwargs must be hashable
- perfect for when you need to periodically call an expensive function with the same arguments
Example:
import timeit from functools import lru_cache import requests @lru_cache(maxsize=10, typed=False) def open_web_page(website_url): requests.get(website_url) without_cache = """ import requests def open_web_page(website_url): requests.get(website_url) urls = [ 'https://testdriven.io', 'https://testdriven.io', 'https://google.com', 'https://google.com', ] for url in urls: open_web_page(url) """ with_cache = """ from functools import lru_cache import requests @lru_cache(maxsize=10, typed=False) def open_web_page(website_url): requests.get(website_url) urls = [ 'https://testdriven.io', 'https://testdriven.io', 'https://google.com', 'https://google.com', ] for url in urls: open_web_page(url) """ print(timeit.timeit(without_cache, number=5)) # => 7.195018381 print(timeit.timeit(with_cache, number=5)) # => 3.6599477370000004
Partial functions in Python with partial from functools
Python tip:
You can use
partial
fromfunctools
to freeze a certain number of arguments from a function and create a new, simplified function.It returns a new partial object which when called will behave like a function called with the positional args and keywords.
An example 👇
from functools import partial all_users = [ {"email": "[email protected]"}, {"email": "[email protected]"}, {"email": "[email protected]"}, ] def _sort_users_by_email(users, sort_order): asc_dsc_to_reverse = { "ascending": True, "descending": False, } return sorted( users, key=lambda user: user["email"], reverse=asc_dsc_to_reverse[sort_order] ) _sort_users_by_email_ascending = partial(_sort_users_by_email, sort_order="ascending") _sort_users_by_email_descending = partial(_sort_users_by_email, sort_order="descending") print(_sort_users_by_email_ascending(all_users)) # [{'email': '[email protected]'}, {'email': '[email protected]'}, {'email': '[email protected]'}] print(_sort_users_by_email_descending(all_users)) # [{'email': '[email protected]'}, {'email': '[email protected]'}, {'email': '[email protected]'}]
Get the unique values from a list of dictionaries
Python tip:
You can use a dictionary comprehension to create a list of dictionaries unique by value on a selected key
users = [ {"name": "John Doe", "email": "[email protected]"}, {"name": "Mary Doe", "email": "[email protected]"}, {"name": "Mary A. Doe", "email": "[email protected]"}, ] print(list({user["email"]: user for user in users}.values())) """ [ {'name': 'John Doe', 'email': '[email protected]'}, {'name': 'Mary A. Doe', 'email': '[email protected]'} ] The same key can occur only once inside a dictionary. Every element from a list is assigned to a key with a value of email. Each new element with the same email overwrites any existing ones. Therefore, only one element is left with the same value on the key. .values() returns a dict_values object containing values from the dictionary, list() converts the dict_values object back to a list. """
Subtracting two lists in Python
Python tip:
To subtract two lists (element by element), you can use a list comprehension and
zip
.
zip
iterates over both lists -> you receive elements with the same index.The list comprehension then creates a new list containing subtracted values.
👇
first = [1, 5, 7] second = [5, 3, 0] print([xi - yi for xi, yi in zip(first, second)]) # => [-4, 2, 7]
Handling missing keys with Python's defaultdict
Python tip:
You can use
defaultdict
to provide a default value for missing keys when accessing or assigning:defaultdict(default_factory)
default_factory
is a function used to initialize the value for the missing key (None
is set by default).If you pass the list constructor as the
default_factory
, adefaultdict
is created with the values that are list.For example:
import json from collections import defaultdict products = [ {"name": "Cold beer", "price": 3.5, "category": "Beer"}, {"name": "Coffee", "price": 1.5, "category": "Warm drinks"}, {"name": "Cappuccino", "price": 2.0, "category": "Warm drinks"}, {"name": "Chicken Sandwich", "price": 3.5, "category": "Snacks"}, {"name": "Vegan Sandwich", "price": 3.5, "category": "Snacks"}, ] products_by_group = defaultdict(list) for product in products: products_by_group[product["category"]].append(product) print(json.dumps(products_by_group, indent=2)) """ { "Beer": [ { "name": "Cold beer", "price": 3.5, "category": "Beer" } ], "Warm drinks": [ { "name": "Coffee", "price": 1.5, "category": "Warm drinks" }, { "name": "Cappuccino", "price": 2.0, "category": "Warm drinks" } ], "Snacks": [ { "name": "Chicken Sandwich", "price": 3.5, "category": "Snacks" }, { "name": "Vegan Sandwich", "price": 3.5, "category": "Snacks" } ] } """
Python Counting - finding the most common occurence
Python tip:
You can use
Counter
from thecollections
module to find the most common element in a:
- string - character with the most occurrences
- dict - key with highest value
- list - element with the most occurrences
most_common(n)
-> returns n most common elementfrom collections import Counter counter = Counter("TestDriven.io tutorials") print(counter.most_common(1)) # character with the most occurrences # => [('t', 3)] counter = Counter({"red": 2, "green": 10, "blue": 7}) print(counter.most_common(1)) # key with the highest value # => [('green', 10)] counter = Counter([0, 2, 1, 1, 4, 10, 33, 21, 12, 10, 1]) print(counter.most_common(1)) # element with the most occurrences # => [(1, 3)]
Python type hints - typing.Literal
Python tip:
You can use
Literal
to indicate that value can be one of the provided literals.Static type checkers will report an error when the value doesn't match one of the provided literals.
https://mypy.readthedocs.io/en/stable/literal_types.html#literal-types
from typing import Literal STATUS = Literal["ACTIVE", "DISABLED"] class User: def __init__(self, username: str, status: STATUS): self.username = username self.status = status user = User("[email protected]", "CREATED") """ mypy example.py example.py:12: error: Argument 2 to "User" has incompatible type "Literal['CREATED']"; expected "Union[Literal['ACTIVE'], Literal['DISABLED']]" Found 1 error in 1 file (checked 1 source file) """
Python type hints - creating a type alias
Python tip:
You can create a type alias to make your code more readable.
from typing import List Vector = List[float] def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector]
Python Type Hints - typing.Union
Python tip:
Use
Union
from thetyping
module to allow any of the listed types.from typing import Union def sum_ab(a: Union[int, float], b: Union[int, float]) -> Union[int, float]: return a + b
Python Type Hints - typing.TypedDict
Python (>=3.8) tip:
You can subclass
TypedDict
to create a type for dictionaries with fixed keys.Static type checking will report an error when there are extra or missing keys.
from typing import TypedDict class Song(TypedDict): name: str year: int song: Song = {"name": "Enter Sandman", "year": 1991, "band": "Metallica"} """ mypy song.py song.py:9: error: Extra key "band" for TypedDict "Song" Found 1 error in 1 file (checked 1 source file) """
Python's final qualifier
Python (>=3.8) tip:
You can use the
final
decorator to declare that a:
- Method should not be overridden
- Class should not be subclassed
You can also use the
Final
annotation to declare that a variable or attribute should not be reassigned, redefined, or overridden. It can be used as indicator to another developer that the given variable should be treated as a constant:from typing import Final _PI: Final = 3.14
A static type check will report an error when it's violated.
https://mypy.readthedocs.io/en/stable/final_attrs.html
from typing import Final, final # example 1 @final class Cat: @final def meow(self): return "Meow" class WildCat(Cat): def meow(self): return "Grrr" # mypy cat.py # error: Cannot inherit from final class "Cat" # example 2 class Foo: @final def bar(self): return "baz" def foobar(): return "foobar" new = Foo() new.bar = foobar # mypy foo.py # error: Cannot assign to final attribute "bar" # example 3 favorite_color: Final[str] = "red" favorite_color = "blue" # mypy foo.py # error: Cannot assign to final name "favorite_color"
Problem solving - what have you tried?
When stuck, spend at least 30 minutes but no more than 60 trying to solve the problem before asking for help. Also, when you ask for help make sure you can answer the question, "What have you tried?”.
Python's platform module
Python tip:
You can check the type of machine and platform that your program is running from with
platform.machine()
andplatform.platform()
, respectively.An example👇
import platform print(platform.machine()) # => x86_64 print(platform.platform()) # => macOS-10.15.6-x86_64-i386-64bit