Table of Contents generated with DocToc
from collections import defaultdict
# 定义一个可形成树的方法
tree = lambda: defaultdict(tree)
# 实例化一个树
database = tree()
database['users']['name'] = 'ecmadao'
# 如果是普通的字典,则对于不存在的多层嵌套的赋值会直接报错
# 必须先 database['users'] = {}
import json
print(json.dumps(database))
# {"users": {"name": "ecmadao"}}
使用这种方式更容易理解:
database = defaultdict(lambda: defaultdict())
database["users"]["name"] = "ecmadao"
提供默认的值,通过一个list生成一个dict
# ⽤序列做 key,并提供默认value
dict.fromkeys(["a", "b", "c"], 1)
# {'c': 1, 'b': 1, 'a': 1}
example = [1, 2, 3, 4]
a, *b, c = example
# a -> 1
# b -> [2, 3]
# c -> 4
使用zip
example = {
'a': 1,
'b': 2,
'c': 3
}
tmp = zip(example.values(), example.keys())
# [(1, 'a'), (2, 'b'), (3, 'c')]
result = dict(tmp)
# {1: 'a', 2: 'b', 3: 'c'}
使用字典推导式
example = {
'a': 1,
'b': 2,
'c': 3
}
elpmaxa = {key: value for value, key in example.items()}
# {1: 'a', 2: 'b', 3: 'c'}
摘自
编程派 -- 怎样合并字典最符合Python语言习惯?
default = {...} # dict 1
info = {...} # dict 2
# method 1
# 手动更新较麻烦
dict_example = default.copy()
dict_example.update(info)
# method 2
# 稍有重复
from itertools import chain
dict_example = dict(chain(default.items(), info.items()))
# method 3
# ChainMap是按照顺序检索字典的,所以info会在default之前返回匹配的值
# 返回值不是字典,而是类似字典的映射
from collections import ChainMap
dict_example = ChainMap({}, info, default)
# method 4
# method 3结果转换为dict
from collections import ChainMap
dict_example = dict(ChainMap({}, info, default))
# method 5
# 最优解
dict_example = {**default, **info} # python 3.5以后版本支持
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(x=11, y=22)
p[0] + p[1] # 33
p.x # 11
p.y # 22
# namedtuple._make(sequence/iterable) 通过序列或生成器来实例化一个命名元组
Point = namedtuple('Point', ['x', 'y'])
p = Point._make([11, 22])
# namedtuple._asdict() 作用于实例化的命名元组,返回一个新的OrderedDict
p._asdict()
# OrderedDict([('x', 11), ('y', 22)])
# namedtuple._replace() 替换命名元组内的某些值并返回新的实例
p._replace(x=33)
# Point(x=33, y=22)
# namedtuple._fields() 返回命名元组中key组成的元组
p._fields()
# ('x', 'y')
命名元组在通过csv
包解析csv文件的时候很有用
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import os
os.listdir(path) # 列出目录下所有文件
os.isfile(path) # 判断是否是文件
os.path.splitext(path) # 把一个文件分为文件名和后缀
os.path.join() # 合并路径
os.path.exists(path) # 检查是否存在
os.makedirs(dir) # 创建文件夹
os.walk(path) # 遍历每个目录将会返回两个列表(一个文件列表,一个目录列表)
High-level file operations
# 复制文件
import shutil
shuilt.copyfile(src, dst)
# 把src复制至dst
使用bs4分析html的时候,可能会遇见DOM解析出错的时候:
target_url = soup.find('a').get('href')
# or
content = soup.find('div', attr={"class": "demo"}).string
如果DOM中没有找到目标元素,还进一步使用get的话,则会报出异常。因此,在没有获取到元素的时候,返回{}就可以避免get出错
target_url = (soup.find('a') or {}).get('href')
添加__slots__
属性,内部指明类的属性名
__slots__ = ['year', 'month', 'day']
定义一个公用的基类,内部定义公用的__init__
函数
class Structure:
_fields = []
def __init__(self, *args): # 缺点:参数定义不明确,不支持关键字参数
if len(args) != len(self._fields):
raise TypeError('Expected {} arguments'.format(len(self._fields)))
# Set the arguments
for name, value in zip(self._fields, args):
setattr(self, name, value)
之后继承基类的其他子类可以避免写繁琐的__init__
方法
class Stock(Structure):
_fields = ['name', 'shares', 'price']
属性的代理访问 -- 代理模式
装饰器 -- 创建可管理的属性
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError('Expected a string')
self._name = value
为什么装饰器返回和设置的是_name
而不是name
?那是因为这样的话,可以在初始化的时候就触发setter
来进行类型的检查。
不要写没有做任何其他额外操作的property。 它会让你的代码变得很臃肿,运行起来变慢很多。
装饰器 -- 子类中扩展property
在子类中扩展一个property可能会引起很多不易察觉的问题, 因为一个property其实是 getter、setter 和 deleter 方法的集合,而不是单个方法。 因此,但你扩展一个property的时候,你需要先确定你是否要重新定义所有的方法还是说只修改其中某一个
# 父类
class Person:
def __init__(self, name):
self._name = name
# Getter function
@property
def name(self):
return self._name
# Setter function
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError('Expected a string')
self._name = value
# 子类
# 只扩展property的getter方法
class SubPerson(Person):
@Person.name.getter
def name(self):
print('Getting name')
return super().name
# 只扩展setter方法
class SubPerson(Person):
@Person.name.setter
def name(self, value):
print('Setting name to', value)
super(SubPerson, SubPerson).name.__set__(self, value)
描述器 -- 创建新的类或实例属性
一个描述器就是一个实现了三个核心的属性访问操作(get, set, delete)的类, 分别为 __get__()
、__set__()
和 __delete__()
# 定义一个描述器
class CheckInteger:
def __init__(self, name):
self.name = name
def __get__(self, instance, cls):
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Expected an int')
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
# 使用描述器
# 需将这个描述器的实例作为类属性放到一个类的定义中
class Point:
x = CheckInteger('x')
y = CheckInteger('y')
def __init__(self, x, y):
self.x = x
self.y = y
# 之后,所有对描述器属性(x或y)的访问会被 __get__() 、__set__() 和 __delete__() 方法捕获到
point = Point(1, 2)
point.x # 调用 Point.x.__get__(point, Point)
point.x = '1' # TypeError('Expected an int')
描述器 -- 实现数据模型的类型约束
import random
foo = (1, 2, 3, 4, 5)
random.choice(foo)
string
有方法能让我们方便的获取所有字母和数字
import string
string.ascii_lowercase # abcdefghijklmnopqrstuvwxyz
string.ascii_uppercase # ABCDEFGHIJKLMNOPQRSTUVWXYZ
string.ascii_letters # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
string.digits # 0123456789
通过random.choice
即可进行随机选择
import string
import random
def id_generator(size=6, chars=None):
chars = chars if chars is not None else string.ascii_letters + string.digits
return ''.join([random.choice(chars) for _ in range(size)])
id_generator() # 随机生成一个混合大小写和数字的六位码
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
# 对字符串对象用isdigit()方法(只能检查是否是整数):
a = "03523"
a.isdigit()
# True
b = "963spam"
b.isdigit()
# False
excel/word/xml/csv
注:openpyxl读取文件类型不支持xls但支持xlsx,可以使用xlrd库进行xls的读取,或者直接将xls转换为xlsx
墙裂推荐xlsxwriter
图像
计算
数据库
其他