Here's my notes about the book fluent python v1.
-- vialon, Feb, 24, 2022
Fluent Python v2(2021) is here, just have English version.
Before Reading
Let me explain the structure of this file.
It won't contain all points but some parts that I think is important in Fluent Python. I divide every chapter into three parts: the important point, the baisc konwlegde point and the summary.
Part - 1: Other Important Points
2.8 Bisect Module
Order list:
-
list.sort()-> return None, but has changed the list object itself! -
sorted(list)-> return [Ordered NewList], never change the list but created a new list object. -
parameter(Both): list, reverse = false, key = (identity function)
-
the difference:
- The
list.sort()function is a list build-in function; sorted()function is a default function;- The return, the list itsele is changed or not;
- The
It's very useful to use this module to control the ordered list.
bisect.bisect(haystack, needle, lo = 0, hi = len(a), *, key = None).
To find the needle's position in the haystack, the parameters 'lo' and 'hi' will determine the range of search(start with 'lo' and the search range is 'hi').
Use Bisect to search and sort the student's score.
import bisect
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
i = bisect.bisect(breakpoints, score)
return grades[i]
[grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
# the result:
# >>> ['F', 'A', 'C', 'C', 'B', 'A', 'A']Python will create a copy of the object in the memory which we are operating,but it'll spend lots of time to finish this work when there comes the float lists containning lots of members, but in fact we don't need create a mapping object so the MemoryView function will be very useful.
MemoryView will return an object without creating the copy object in memory and it'll reduce the memory cost and improve the running speed by using buffer protocol.
Syntax: MemoryView(Obj) -> Obj.
Part - 2: Basic Knowledge Points
According to Python Cicada and in order to improve the code readablity, we create list comprehension and generator expression in python.
The purpose of Listcomps is just creating a list:
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
tshirts = [(color, size) for color in colors for size in sizes]
#>>> tshirts
# [('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]You can also use if...else... syntax in it; It's a closure environment.
Different from Listcoms, Genexps show better in creating iterative list and combining with other list-container. It'll provide great help with the memory cost compared with its brother.
In form, Genexps just replace the '[]' with '()' based on Listcomps.
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):
print(tshirt)
#printout -> :
#>>> black S
#>>> black M
#>>> black L
#>>> white S
#>>> white M
#>>> white L-
Function filter and map:
Filter function receivers two parameters and return an iterative object, it'll filter out the elements which couldn't go through the judge function:
parameter -> judge function, iterative object. return -> generator object.
u can use
list()function to change the object into a list if u need a list.a = [1, 2, 4, 'x', 'y', 5] b = filter(lambda c:isinstance(c, int), a) print(b) # >>> <filter object at 0x000001C7385B2F70> list(b) # >>> [1, 2, 4, 5]
Map function also receivers several parameters and return an iterative object, it'll create a functional mapping among the parameters:
parameter -> function/iterative object. return -> generator object.
def square(x): return x ** 2 map(square, [1,2,3,4,5]) # >>> <map object at 0x100d3d550> list(map(square, [1,2,3,4,5])) # >>> [1, 4, 9, 16, 25]
Comared with combination of filter and map, Listcomps seems like more pythonic.1
>>> symbols = '$¢£¥€¤' >>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127] >>> beyond_ascii [162, 163, 165, 8364, 164] >>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols))) >>> beyond_ascii [162, 163, 165, 8364, 164]
It's a mistake that just regard Tuple as stable List type, this pretty young thing will provide a container to store separate data and their location information.
Different from List, Tuple is usually used to store mussy or no-named data while List always contains data with same type.
-
Unpark Tuple
We can combine the mussy data into several useful groups through Tuple Unpark or extract the useful data from tuple if there have some useless informations.
In fact, the List type is also support with the unpark operation.
metro_areas = ('Tokyo','JP',36.933,(35.689722,139.691667)) city, country, pop, location = metro_areas print(city, country, pop, location) # >>> Tokyo JP 36.933 (35.689722, 139.691667) # we just want the city and location city, *other, (_, latitude) = metro_areas print(city, other, latitude) # >>> Tokyo ['JP', 36.933] 139.691667
Yes, it's a good idea using
_placeholder and*operator to deal with the remainder, but the operator*should appear just once time in a single code line. Seemingly we can also found it that the unpark operation can be used in nested tuple. -
NamedTuple
NamedTuple is a factory function, which creates a named-tuple template class and can be very useful in analyse data and debug code.
NameTuple inherits most property from Tuple
from collections import namedtuple # It's packed in collections module city = namedtuple('city', 'name country population coordinates') Tokyo = city('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) print(Tokyo.country, Tokyo.population, Tokyo.coordinates) # >>> JP 36.933 (35.689722, 139.691667) print(Tokyo[1]) # >>> JP
Part - 3: The Summary
May it's suitable putting the important knowledge points here, I privately think.
-
Container List:
list,tuple,collections.deque(store different types of data.) -
Flat List:
str,bytes,bytearray,memoryview,array.array(data must have same type.)
This part is mainly about Pythonista(python master) Code.
Python, as the most hightest readablity language and its creation philosophy, can create popular and easy-to-understand code.
So we should follow the Python Zen:
# import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
...
Recently, I had did some programs with my boss, and he did some code guideance to me, which made me realize the importance of code quality. So I had read the book -- The Hitchhiker’s Guide to Python
Decorator, as one of the most successful Design Patterns, has been used in many programming languages, as well as in Python. Decorator means that we can add some decorations for our specific functions, in anothe way -- add some extra features to the function.
In Python, we can regard the decorator as specific function which packages the target function, and use it as the syntax sugar @ before the target function.
Let's have an instance.
from time import time
# the decorator --> calculate the function run time
def timer(func):
def inner_func(*args, **kwargs):
print('here is the real function.')
start_time = time()
result = func(*args, **kwargs)
end_time = time()
print(f'the function {func.__name__} costs {end_time - start_time}s.')
return result
return inner_func
@timer
def test_func():
x, res = 1, 0
for i in range(100000):
res = res + x * i
x += 1
return res
test_func()
# the console:
# >>> here is the real function.
# >>> the function test_func costs 0.005997180938720703s.
# >>> 333333333300001The decorator can also add some parameters as normal function, but when doing this, we need package the decorator first, the function structure will be this:
the decorator --- get the real decorator's parameters
the real decorator --- get the target function
the inner function --- get the target function's parameters
import os, time
def fatory_decorator(active = False):
#get the decorator's parameters -> active
def decorator(func):
# the decorator is the real decorator of function
print('here here')
def clock(*arg, **kwargs):
# the addition function of the decorator
start_time = time.time()
if active:
print(arg, kwargs)
else:
print('active has closed.')
func_return = func(*arg, *kwargs)
run_time = time.time() - start_time
return func_return, run_time
return clock
return decorator
@fatory_decorator(active = True)
def func1(arr: list, sleep_time = 5):
time.sleep(sleep_time)
print('Here start game.')
temp_sum = 0
for i in range(len(arr)):
arr[i] = arr[i] + temp_sum
temp_sum = arr[i]
return arr
temp_list = [1,2,3,4,5]
arr, run_time = func1(temp_list, 6)
print(f'the function {func1.__name__} get a list and return the list {arr} after running {round(run_time, 2)} seconds.')
# >>> here here
### freeze 6s there
# >>> Here start game.
# >>> the function clock get a list and return the list [1, 3, 6, 10, 15] after running 6.01 seconds.We can also find that the class decorator like in Flask:
# creat a flask app
from flask import Flask, request, jsonify
from flask_cors import CORS
# enable CORS(cross-origin-resource-share)
app = Flask(__name__)
CORS(app)
# specify index route to the server
@app.route('/', method = ['GET', 'POST'])
def index():
return 'OK'
if __name__ == '__main__':
app.run(host = 'localhost', port = 8080, debug = True)In this Flask instance, we can see there comes the class decoretor app.route, in fact, decorator can be created inside an object like this:
# create a class decorator
# outter decorator
class Temp:
num = 1
cot = 0
def count(func):
def inner(*args, **kwargs):
print(f'we have call the funcion count times.')
return func(*args, **kwargs)
return inner
@Temp.count
def test(num):
print(num)
test(1)
# the resule:
# >>> we have call the funcion count times.
# >>> 1But when we wanna call the class's attribute cls.cot, this function will raise error TypeError: Temp.count() takes 1 positional argument but 2 were given, so we should update our function:
# inner class decorator
class Temp:
num = 1
cot = 0
def inner_count(func):
def inner(self, *args, **kwargs):
print(f'we have call the funcion count times.')
print(f'we get {self.cot} attribute.')
return func(self, *args, **kwargs)
return inner
@inner_count
def test(self, num):
print(num)
Temp().test(1)
# the result:
# >>> we have call the funcion count times.
# >>> we get 0 attribute.
# >>> 1There, there, here are the common decorators used in diary work. You can also read this article -- Python Decorator(zh_cn), it has similar demonstration. :)
Footnotes
-
The Zen of Python -> Pythonic: Firstly, as a python engineer, we must walk like a python and this way is called pythonic 😗. ↩