Improve your Python knowledge and skills
Improve your Python knowledge and skills
开始使用 py3+
从 2020-01-01
开始 python 2 官方不再支持
Python 2 is officially not supported as of January 1, 2020.
检查python版本
保证脚本和python解释器的一致
make sure your users are not running your script with an incompatible version
import sys
if not sys.version_info > (2, 7):
...
# berate your user for running a 10 year
# python version
elif not sys.version_info >= (3, 5):
...
# Kindly tell your user (s)he needs to upgrade
# because you're using 3.5 features
使用ipython
ipython不仅是一个增强型(自动补全)的shell
In [1]: mylist = [i for i in range(1, 10)]
In [2]: print(mylist)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: mylist
Out[3]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
后边加问号, 查看变量信息
In [4]: mylist?
Type: list
String form: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Length: 9
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
补全
In [5]: mylist.
append() count() insert() reverse()
clear() extend() pop() sort()
copy() index() remove()
还有支持许多内置的命令行命令:
%cd — to change the current working directory
%edit — to open an editor and execute the code you typed in after closing the editor
%env — to show the current environment variables
%pip install [pkgs] — to install packages without leaving the interactive shell
%time and %timeit — to time the execution of Python code
支持 全局的
In-list
,Out-dict
变量
In and Out are actual objects. You can use the output of the 3rd command by using Out[3]
In [5]: In
Out[5]: ['', 't = "a', 't = "a"', 'In[1]', 'In[2]', 'In']
In [8]: Out
Out[8]: {2: 'a', 7: [1, 2, 3, 4, 5, 6, 7, 8, 9]}
List Comprehensions 列表表达式
[ expression for item in list if conditional ]
# basic
mylist = [i for i in range(10)]
print(mylist)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# do some math:
squares = [x**2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# call function
def some_function(a):
return (a + 5) / 2
my_formula = [some_function(i) for i in range(10)]
print(my_formula)
# [2, 3, 3, 4, 4, 5, 5, 6, 6, 7]
# condition filter
filtered = [i for i in range(20) if i%2==0]
print(filtered)
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
查看对象的内存占用
sys.getsizeof()
range function
returns a class that only behaves like a list. A range is a
lot more memory efficient
than using an actual list
of numbers.
# 使用 range
import sys
mylist = range(0, 10000)
print(sys.getsizeof(mylist))
# 48
# range function returns a class that only behaves like a list. A range is a
# lot more memory efficient than using an actual list of numbers.
import sys
myreallist = [x for x in range(0, 10000)]
print(sys.getsizeof(myreallist))
# 87632
多个返回值 (超过3个值
应该放在(data)类
中)
python的函数支持多返回值
def get_user(id):
# fetch user from database
# ....
return name, birthdate
name, birthdate = get_user(4)
This is alright for a limited number of return values. But anything past 3 values should be put into a (data) class.
使用数据类 data classes
py3.7+
Python 提供 数据类 data classes
与常规类
或其他替代方法(如返回多个值或字典)
相比,它具有多个优点:
-
减少代码量, a data class requires a minimal amount of code
-
可以进行比较, 因为实现了
__eq__
, you can compare data classes because__eq__
is implemented for you -
debugging
的时候可以打印详细的信息
, 因为实现了__repr__
, you can easily print a data class for debugging because__repr__
is implemented as well -
进行了
类型hint
,减少数据类型bug, data classes requiretype hints
, reduced the chances of bugs
# 传统实现
class RegularCard:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def __repr__(self):
return (f'{self.__class__.__name__}'
f'(rank={self.rank!r}, suit={self.suit!r})')
def __eq__(self, other):
if other.__class__ is not self.__class__:
return NotImplemented
return (self.rank, self.suit) == (other.rank, other.suit)
# 使用数据类 data class
from dataclasses import dataclass
@dataclass
class Card:
rank: str
suit: str = "hearts" # 位置参数, 设置默认值
card = Card("Q", "hearts")
print(card == card)
print(card.__eq__(card))
print(card.__repr__()) # Card(rank='Q', suit='hearts') __repr__
变量交换值
a = 1
b = 2
a, b = b, a
print (a)
# 2
print (b)
# 1
更好的字典合并方法 py3.5+
可以用来进行多个字典的去重
dict1 = { 'a': 1, 'b': 2 }
dict2 = { 'b': 3, 'c': 4 }
merged = { **dict1, **dict2 }
print (merged)
# {'a': 1, 'b': 3, 'c': 4}
把字符串与list的互相转换
# 字符串 -->> list
mystring = "The quick brown fox"
mylist = mystring.split(' ')
print(mylist)
# ['The', 'quick', 'brown', 'fox']
# list -->> 字符串
mylist = ['The', 'quick', 'brown', 'fox']
mystring = " ".join(mylist)
print(mystring)
# 'The quick brown fox'
使用 表情emoji
import emoji
result = emoji.emojize('Python is :thumbs_up:')
print(result)
# 'Python is 👍 '
# You can also reverse this:
result = emoji.demojize('Python is 👍 ')
print(result)
# 'Python is :thumbs up:'
列表切片
a[start:stop:step]
# We can easily create a new list from
# the first two elements of a list:
first_two = [1, 2, 3, 4, 5][0:2]
print(first_two)
# [1, 2]
# And if we use a step value of 2,
# we can skip over every second number
# like this:
steps = [1, 2, 3, 4, 5][0:5:2]
print(steps)
# [1, 3, 5]
# This works on strings too. In Python,
# you can treat a string like a list of
# letters:
mystring = "abcdefdn nimt"[::2]
print(mystring)
# 'aced it'
# 逆序列表和字符串 Reversing strings and lists
revstring = "abcdefg"[::-1]
print(revstring)
# 'gfedcba'
revarray = [1, 2, 3, 4, 5][::-1]
print(revarray)
# [5, 4, 3, 2, 1]
使用set
去重list和字符串
mylist = [1, 1, 2, 3, 4, 5, 5, 5, 6, 6]
print (set(mylist))
# {1, 2, 3, 4, 5, 6}
# And since a string can be treated like a
# list of letters, you can also get the
# unique letters from a string this way:
print (set("aaabbbcccdddeeefff"))
# {'a', 'b', 'c', 'd', 'e', 'f'}
查找可迭代对象中最多的元素 (max(set(iterable), key=iterable.count)
)
import time
test = [12, 2, 8, 6, 17, 9, 4, 8, 5, 11, 7, 4, 5, 16, 19, 10, 15, 19, 2, 19, 8, 19, 7, 8, 16, 1, 2, 18, 12, 1, 18, 14, 12, 7, 17, 11, 18, 1, 17, 9, 5, 12, 1, 2, 19, 4, 2, 17, 9, 4, 7, 9, 12, 8, 11, 13, 7, 8, 15, 10, 12, 2, 9, 6, 4, 19, 10, 14, 11, 15, 4, 10, 13, 2, 15, 12, 17, 19, 3, 1, 8, 2, 2, 8, 10, 13, 1, 17, 16, 15, 1, 9, 6, 11, 16, 1, 17, 13, 13, 3, 16, 9, 15, 5, 6, 16, 15, 5, 6, 19, 2, 2, 16, 13, 7, 7, 19, 19, 15, 17, 1, 5, 16, 19, 9, 2, 4, 4, 8, 10, 11, 6, 13, 16, 3, 8, 19, 7, 3, 13, 8, 19, 19, 18, 19, 3, 4, 8, 6, 1, 8, 4, 16, 12, 10, 14, 4, 17, 19, 19, 9, 18, 16, 16, 8, 17, 16, 13, 4, 14, 13, 11, 9, 14, 17, 10, 6, 12, 9, 3, 1, 9, 6, 16, 4, 5, 13, 17, 17, 9, 14, 15, 10, 10, 11, 8, 3, 5, 4, 8, 9, 8, 8, 1, 1, 6, 7, 11, 8, 15, 3, 11, 12, 7, 17, 19, 17, 14, 18, 5, 17, 16, 9, 19, 11, 17, 11, 13, 6, 7, 1, 6, 13, 6, 7, 16, 15, 3, 3, 9, 9, 17, 7, 18, 13, 18, 4, 10, 19, 2, 10, 1, 2, 4, 16, 13, 18, 12, 13, 19, 13, 11, 11, 6, 12, 7, 5, 19, 7, 10, 12, 11, 18, 14, 9, 3, 1, 2, 13, 16, 15, 18, 14, 1, 1, 18, 6, 4, 5, 6, 10, 9, 1, 9, 15, 6, 5, 11, 12, 4, 11, 12, 5, 16, 11, 15, 7, 3, 16, 12, 7, 2, 6, 6, 14, 13, 8, 5, 17, 15, 12, 18, 7, 8, 12, 8, 19, 10, 4, 14, 18, 15, 3, 13, 17, 14, 9, 2, 6, 5, 18, 12, 19, 17, 1, 17, 15, 10, 14, 2, 12, 14, 12, 9, 11, 17, 16, 19, 17, 19, 19, 8, 2, 6, 8, 11, 1, 6, 4, 15, 5, 13, 14, 16, 12, 16, 5, 3, 5, 9, 16, 3, 6, 19, 11, 7, 13, 11, 14, 12, 17, 4, 16, 13, 7, 19, 3, 4, 8, 18, 7, 13, 10, 7, 8, 18, 3, 12, 11, 12, 18, 4, 13, 14, 13, 6, 7, 2, 11, 8, 12, 7, 6, 10, 11, 2, 9, 14, 8, 3, 8, 2, 4, 19, 5, 4, 5, 8, 6, 3, 7, 4, 15, 10, 18, 19, 19, 4, 5, 6, 10, 13, 12, 10, 4, 15, 12, 1, 12, 10, 17, 4, 3, 3, 7, 8, 2, 12, 19, 2, 14, 13, 10, 6, 10, 9, 9, 3, 5, 7, 14, 1, 17, 9, 5, 2, 9, 19, 1, 5, 8, 11, 14, 10, 17, 2, 6, 17, 17, 7, 15, 1, 5, 10, 11, 12, 19, 11, 10, 14, 16, 19, 13, 16, 6, 14, 1, 7, 19, 3, 7, 2, 4, 4, 19, 6, 2, 4, 10, 5, 13, 4, 14, 5, 7, 15, 9, 2, 15, 10, 18, 2, 15, 6, 5, 4, 13, 19, 5, 11, 17, 10, 12, 15, 15, 14, 9, 9, 16, 12, 3, 13, 1, 8, 3, 7, 4, 15, 3, 18, 8, 11, 15, 12, 2, 6, 1, 7, 1, 10, 17, 2, 18, 14, 3, 1, 15, 15, 8, 9, 11, 7, 12, 5, 5, 14, 5, 19, 19, 4, 13, 2, 15, 13, 17, 10, 14, 8, 6, 6, 12, 17, 4, 4, 18, 9, 4, 6, 19, 19, 7, 13, 14, 11, 16, 2, 2, 13, 19, 10, 19, 3, 13, 9, 19, 4, 6, 5, 14, 6, 15, 12, 8, 2, 9, 19, 8, 14, 10, 15, 14, 13, 7, 14, 3, 2, 2, 16, 14, 2, 18, 2, 17, 9, 13, 2, 10, 18, 9, 17, 18, 8, 11, 3, 18, 10, 15, 1, 16, 1, 18, 10, 12, 1, 17, 15, 4, 6, 15, 8, 9, 5, 15, 16, 10, 6, 2, 1, 15, 16, 8, 4, 2, 7, 16, 9, 15, 15, 9, 13, 16, 6, 10, 10, 12, 9, 7, 13, 4, 3, 2, 15, 8, 7, 7, 5, 12, 8, 16, 18, 6, 17, 5, 8, 6, 7, 9, 5, 11, 7, 14, 5, 15, 15, 10, 15, 13, 15, 10, 12, 8, 13, 2, 8, 12, 6, 10, 5, 12, 9, 1, 15, 14, 2, 11, 2, 8, 3, 3, 7, 9, 7, 12, 10, 14, 15, 14, 10, 15, 10, 19, 5, 16, 2, 8, 7, 15, 8, 18, 10, 14, 4, 19, 15, 8, 13, 8, 11, 5, 10, 9, 18, 15, 1, 6, 7, 15, 13, 9, 12, 1, 2, 11, 19, 12, 8, 2, 16, 10, 3, 6, 5, 18, 14, 1, 5, 15, 19, 1, 12, 16, 1, 4, 12, 18, 13, 6, 13, 1, 2, 2, 9, 19, 7, 15, 2, 7, 16, 3, 8, 17, 4, 7, 3, 9, 19, 19, 15, 19, 4, 17, 11, 1, 19, 17, 13, 17, 7, 10, 11, 9, 17, 17, 14, 10, 7, 10, 7, 5, 5, 4, 19, 6, 17, 19, 9, 5, 10, 7, 13, 3, 19, 17, 4, 12, 18, 5, 6, 16, 12, 17, 5, 4, 7, 9, 10, 15, 7, 3, 6, 19, 17, 14, 17, 2, 2, 1, 14, 5, 6, 1, 2, 7, 6, 7, 6, 6, 4, 14, 18, 8, 1, 6, 3, 14, 2, 3, 2, 11, 19, 18, 14, 11, 3, 2, 11, 12, 17, 17, 7, 11, 18, 15, 2, 1, 19, 1, 8, 17, 15, 2, 10, 9, 3, 12, 12, 6, 10, 15, 11, 2, 3, 14, 18, 13, 3, 10, 19, 10, 2, 9, 6, 19, 15, 7, 12, 4, 14, 17, 5, 6, 15, 5, 6, 8, 10, 8, 13, 17]
# test = "dasdasdsdddddddasdasdsaddddddd"
start = time.perf_counter()
print(max(set(test), key=test.count)) # 19 0.0003058000000000019
# 去重之后, 速度更快, 减少了无效的操作
print(max(test, key=test.count)) # 19 0.0158793
print(time.perf_counter() - start )
# max 返回列表中的最大值,
# key是用来进行排序的函数,
# 用set 來對列表去重, 减少无效的操作
多行字符串
s1 = """Multi line strings can be put
between triple quotes. It's not ideal
when formatting your code though"""
s2 = (
"Multi line strings can be put",
"between triple quotes. It's not ideal",
"when formatting your code though"
)
s3 = "Multi line strings can be put" \
"between triple quotes. It's not ideal" \
"when formatting your code though"
查看,元素计数 Counter
from collections import Counter
mylist = [1, 1, 2, 3, 4, 5, 5, 5, 6, 6]
c = Counter(mylist)
c.update({1: 1, 2: 1, 'a': 1})
print(c) # Counter({1: 3, 5: 3, 2: 2, 6: 2, 3: 1, 4: 1, 'a': 1})
print(c.most_common()) # [(1, 3), (5, 3), (2, 2), (6, 2), (3, 1), (4, 1), ('a', 1)]
# And it works on strings too:
print(Counter("aaaaabbbbbccccc"))
# Counter({'a': 5, 'b': 5, 'c': 5})
文本加颜色
# pip install colorama
from colorama import Fore, Back, Style
print(Fore.RED + 'some red text')
print(Back.GREEN + 'and with a green background')
print(Style.DIM + 'and in dim text')
print(Style.RESET_ALL)
print('back to normal now')
关于日期的使用 ` python-dateutil`
pip3 install python-dateutil
fuzzy parsing of dates from log files and such.
可以高效的解析log日期
from dateutil.parser import parse
logline = 'INFO 2020-01-01T00:00:01 Happy new year, human.'
timestamp = parse(log_line, fuzzy=True)
print(timestamp)
# 2020-01-01 00:00:01
在不能使用常规 datetime
库的时候, 使用 ` python-dateutil`
where the regular Python datetime functionality ends, python-dateutil comes in
整除 Integer division
py2
# Python 2
5 / 2 = 2 # defaults to an integer division,
5 / 2.0 = 2.5 # , unless one of the operands is a floating-point number
py3
Python 3
5 / 2 = 2.5 # defaults to a floating-point division
5 // 2 = 2 # // operator has become an integer division
使用charde
获取字符串的字符编码格式 Charset detection with charde
pip install chardet
https://github.com/chardet/chardet/blob/master/docs/usage.rst
import urllib
from chardet.universaldetector import UniversalDetector
usock = urllib.urlopen('http://yahoo.co.jp/')
detector = UniversalDetector()
for line in usock.readlines():
detector.feed(line)
if detector.done: break
detector.close()
usock.close()
print(detector.result)
# {'encoding': 'EUC-JP', 'confidence': 0.99}
使用 enum 枚举类型
替代数字字面量 直接出现在代码里的数字
提升代码可读性
提升代码正确性
# 避免直接使用 数字字面量
def mark_trip_as_featured(trip):
"""将某个旅程添加到推荐栏目
"""
if trip.source == 11:
do_some_thing(trip)
elif trip.source == 12:
do_some_other_thing(trip)
...
return
# 使用enum
# -*- coding: utf-8 -*-
from enum import IntEnum
class TripSource(IntEnum):
FROM_WEBSITE = 11
FROM_IOS_CLIENT = 12
def mark_trip_as_featured(trip):
if trip.source == TripSource.FROM_WEBSITE:
do_some_thing(trip)
elif trip.source == TripSource.FROM_IOS_CLIENT:
do_some_other_thing(trip)
... ...
return
使用无穷大 float("inf")
与 无穷小 float("-inf")
用來设置一个默认值
# 排序
user = {"tom": 19, "jenny": 13, "jack": None, "andrew": 43}
u = sorted(user, key=lambda item: user.get(item) or float("inf"), reverse=True)
print(u)
# 循环初始值
max_num = float("-inf")
for i in [23, 36, 71, 3]:
if i > max_num:
max_num = i
print(max_num)
使用类
来实现 装饰器
# 1 函数式的装饰器
def delay(func):
def inner(*option, **kw):
...
ret = func(*option, **kw)
...
return ret
return inner
@delay
def foo():
...
foo()
# 1.5 带参数
import time
import functools
def delay(duration:int, func):
def inner(*option, **kw):
...
time.sleep(duration)
ret = func(*option, **kw)
...
return ret
return inner
def delay_param(duration):
return functools.partial(delay, duration)
# 借用partial, 返回带param的 delay装饰器函数
@delay_param(duration=3)
def foo():
...
foo()
# 2 类装饰器
class DelayFunc(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
...
ret = self.func(*args, **kwargs)
...
return ret
@DelayFunc # delay(duration=3)(foo)()
def foo():
...
foo()
# 2.5 带参数
import time
import functools
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def delay_param_cls(duration):
return functools.partial(DelayFunc, duration)
# 返回 带固定参数的 DelayFunc类
@delay_param_cls(duration=3) # delay(duration=3)(foo)()
def foo():
...
foo()