Build a production-ready web application Part 1: Python Basics
This article helps the software engineers who have Web development experience in other languages to migrate to Python Web development quickly, it contains several parts like basics, web development part, etc.
Context
I’m a developer who used Golang in the recent 4 years, I’m getting used to Golang and its framework, because of my team’s preference, we chose Python 3 as the new project’s language, I wanted to write Python code as well as possible in a short time. Because the core of Web development is the same no matter what language it is, I just need to migrate my Web knowledge to Python 3.8+.
This is the checklist of all the essential knowledge I sorted out in the last month.
Python Basics
First, let’s recap the most basic Python syntax. (PS: I’ll mix different languages’ syntax when I switch languages very often, the common case is that I wrote for i in items
in Golang)
Entrypoint
1 | if __name__ == '__main__': |
If-else statement
1 | a = 1 |
Common data structures
It contains array, set, dictionary, tuple.
1 | # array |
Iteration
To iterate an array, list, set, dictionary, you can always use for … in
, also it allows you to create an iterable object which contains the iterable object returned by __iter__
and the way to fetch next object by __next__
.
1 | # iterate arr |
Function
It contains traditional function and anonymous function like the other languages.
Traditional function is the one with def
keyword, name of function and function body.
1 | # sum_two accepts two int parameters and return the sum of them. |
We also want variable parameters sometimes, we can add *
before the parameter and the parameter will accept multiple parameters, type type of args
is tuple.
1 | # sum_all accepts multiple integer parameters and sum them up. |
We want to accept variable name parameters, we can add **
before the parameter and the parameter will receive key=value
pairs.
1 | def print_vars(**kwargs): |
Note that the **kwargs
parameters should be at the end of the parameter list, otherwise it’s not straightforward for the Python interpreter to parse the parameters afterwards.
For anonymous functions, we use lambda
as the keyword, it can accept multiple parameters but only one expression in the body.
1 | sum_two = lambda num1, num2: num1 + num2 |
It’s super useful when you’re using some map, filter, sort, etc and it accepts a lambda function.
1 | # map |
Class definition
The class definition starts with class
keyword, the class contains some functions by convention, like the constructor function __init__
, method call __call__
which allows you to call the class instance like a function.
The self
parameter appears for those instance functions, it’s the this
keyword in other languages, a pointer to the instance itself, it’s always as the first parameter.
1 | class Sample: |
There are also class functions whose scope is the class, the first parameter is cls
instance, they will be introduced in the decorators section.
Decorators
A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure.
1 | def echo_first(f): |
In this sample, it’s a simple function decorator that print echo
first before the method is called.
There are some common used decorators we can use, @staticmethod
prevents the method access to the class or instance, @classmethod
limits the access to the class itself, instance_method
has the biggest scope.
1 | class Test: |
There is @property
decorator to call the setter/getter/deleter of the property in a native way,
1 | class PropertyTest: |
Error handling
1 | try: |
Concurrency
Coroutines are very similar to threads. However, coroutines are cooperatively multitasked, whereas threads are typically preemptively multitasked. Coroutines provide concurrency but not parallelism. The advantages of coroutines over threads are that they may be used in a hard-realtime context (switching between coroutines need not involve any system calls or any blocking calls whatsoever), there is no need for synchronization primitives such as mutexes, semaphores, etc. in order to guard critical sections, and there is no need for support from the operating system.
The Python doc gives several examples of how to define coroutines and execute them,
1 | import asyncio |
They can’t be executed as the normal methods, if you call main()
directly, it returns a coroutine object, to execute it you need pass it to asyncio.run.
To run the coroutines concurrently, you can wrap the coroutine to task by asyncio.create_task
,
1 | async def main(): |
It will run for around 2 seconds instead of 4 seconds.
Awaitables
We say that an object is an awaitable object if it can be used in an
[await](https://docs.python.org/3/reference/expressions.html#await)
expression.
- Coroutines: the
async def
functions - Tasks: used to schedule coroutines concurrently, created by
asyncio.create_task
- Futures: A Future is a special low-level awaitable object that represents an eventual result of an asynchronous operation.
End
Next Artitlce contains the toolkit of setting up the Web application using FastAPI framework, also it will contain the code format, linter, docker image, etc.