做者:半载流殇 连接:https://zhuanlan.zhihu.com/p/35219750 来源:知乎 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。 Pythonic,简言之就是以Python这门语言独特的方式写出既简洁又优美的代码!笔者精心整理了许多实用的Python tricks,想要提升效率、写出高质量的Python代码的话此文必看。 注:请将Python更新到3.6版,方能完美运行本文的全部代码。字符串格式化字符串在字符串前加f,就能够在里面用大括号嵌入变量了(能够代替format函数)>>> a = 5 >>> b = 10 >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.' 'Five plus ten is 15 and not 30.' 字符串拼接>>> text = ['I', ' Love ', 'Python!'] >>> print(''.join(text)) I Love Python! 字符串的contains>>> 'ov' in 'love' True 反转元素>>> 'Love'[::-1] 'evoL' >>> for e in reversed([1,3,5]): print(e) 5 3 1 去除非法字符串保存文件时,咱们必须去除一些非法字符串,此处利用any函数实现def rectify(name): if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]): name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]]) return name HTML转义>>> import html >>> html.unescape('<') '<' >>> html.escape('<') '<' 函数可变参数*args:任意数量的位置参数,可被打包成元组。**kwargs:任意数量的关键词参数,可被打包成字典。打包def foo(*args, **kwargs): print(f"args: {args}") print(f"kwargs: {kwargs}") >>> foo(1,2,3,4, a=1,b=2,c=3) args: (1, 2, 3, 4) kwargs: {'a': 1, 'b': 2, 'c': 3} 解包def foo(x, y): print(x, y) alist = [1, 2] adict = {'x': 1, 'y': 2} >>> foo(*alist) 1, 2 >>> foo(**adict) 1, 2 装饰器装饰器的主要用途:打印日志、检测性能、数据库事务、URL路由它本质上就是一个高阶函数,它接收一个函数做为参数,而后,返回一个新函数。想理解装饰器,就得知道如下两点:1. 函数皆对象2. 闭包特性(内函数能捕捉到外函数的环境变量)简单的日志函数from datetime import datetime import functools def log(f): @functools.wraps(f) def wr(*args, **kwargs): print(f'call {f.__name__}() at {datetime.now()}') return f(*args, **kwargs) return wr @log def square(x): return x ** 2 >>> square(2) call square() at 2018-01-24 11:01:19.547516 4 注意到为了让@deco自适应任何参数定义的函数,咱们将可变参数args, *kwargs做为了wr的参数@functools.wraps(f)为了防止wr的函数属性覆盖掉原函数的属性,咱们必须利用@functools.wraps(f)来把原函数的全部属性复制到新函数里# 不加@functools.wraps(f)的状况下 >>> square.__name__ 'wr' # 加了@functools.wraps(f)的状况下 >>> square.__name__ 'square' 若是想给装饰器传递参数,那么你必须利用闭包特性再嵌套一层函数,不过这并不经常使用。函数性能检测def perf(f): @functools.wraps(f) def wr(*args, **kwargs): start = time.time() r = f(*args, **kwargs) end = time.time() print(f'call {f.__name__}() in {end - start}') return r return wr @perf def test(x): time.sleep(2) return x >>> test(5) call test() in 2.0007083415985107 5 数据库的cursordef link_mysql(fun): def wr(*args, **kwargs): with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur: fun(cur, *args, **kwargs) return wr @link_mysql def insert_data(cur, ...): # execute your sql here. 上下文管理器应用文件操做(超经常使用)、进程互斥锁和支持上下文的其余对象目的是为了代替try语句和简化语法以文件操做为例:利用它,文件会自动打开和关闭with open('/path/to/file', 'r') as f: handle_f 上下文语句支持嵌套(nested)例如将a文件的源数据写入b文件里:with open('a.txt') as i, open('b.txt') as o: o.write(i.read()) 实质经过上下文管理协议__enter__和__exit__来实现Python有个库contextlib利用生成器简化了这种实现,如下是大致框架from contextlib import contextmanager @contextmanager def make_context() : # enter try: yield <value> except Exception as e: # handle_err finally: # exit with make_context() as <value>: # handle_value 如下是with语句操做文件的实质因为自定义,函数名用my_open,但功能和open几乎同样@contextmanager def my_open(filename, mode): f = open(filename, mode) try: yield f except Exception as e: raise e finally: f.close() with my_open('/path/to/file', 'r') as f: handle_f 偏函数partial()用于把一个函数的某些参数给固定住(也就是设置默认值),并返回一个新的函数。def int2(x, base=2): return int(x, base) 至关于:import functools int2 = functools.partial(int, base=2) 数据结构元组元组是一个immutable对象,有如下重要性:- 性能优化- 线程安全- 能够做为dict的key(hashable)- 拆包特性元组拆包a, b = b, a两个数字交换的原理就是它。如下是利用它来获取文件名及其扩展名>>> import os >>> filename, ext = os.path.splitext('patch.exe') >>> filename 'patch' >>> ext 'exe' 更多的解包方式(_表明舍弃,*表明可变长元组)>>> t = (1, 2, 3, 4) >>> first, *middle, last = t >>> middle [2, 3] >>> _, *rest = t >>> rest [2, 3, 4] 列表切片若是想要获取列表的多个元素,就得用到切片list[start:stop:step] 你甚至能够给切片命名,加强复用性和可读性:s = slice(start,stop,step) list[s] 切片的原理是序列协议class Seq: def __getitem__(self, index): return index >>> s = Seq() >>> s[1:5:2] slice(1, 5, 2) 以上实现的是不可变序列协议,若是可变的话还要添加__setitem__()若是在运行时添加协议的话也行,这叫猴子补丁>>> def set_item(self, key, value): self[key] = value >>> classname.__setitem__ = set_item 列表推导式这是Python最强大的几个特征之一。格式也很简单,其中if条件能够省略,for循环能够有多个[i for i in iterable if condition] 10-20全部偶数的平方:[i*i for i in range(10, 21) if i % 2 == 0 ] 一行实现快排def qsort(arr): return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]]) 索引迭代enumerate()能够把一个list变成索引-元素对。for i, value in enumerate(['A', 'B', 'C']): print(i, value) 0 A 1 B 2 C zipzip()能够将可迭代的对象做为参数,将对象中对应的元素打包成一个个元组,并返回一个迭代器,经常使用于同时遍历两个可迭代对象。>>> li1 = ['Python' ,'JavaScript', 'Java'] >>> li2 = [1, 2, 3] >>> nl = zip(li1, li2) <zip object at memory> >>> list(nl) [('Python', 1), ('JavaScript', 2), ('Java', 3)] 配合dict能够生成字典>>> l1 = ['A', 'B', 'C'] >>> l2 = [1, 2, 3] >>> dict(zip(l1, l2)) {'A': 1, 'B': 2, 'C': 3} append和extend>>> x = [1, 2, 3] >>> x.extend([4, 5]) >>> x [1, 2, 3, 4, 5] >>> x.append([6, 7]) >>> x [1, 2, 3, 4, 5, [6, 7]] 集合运算首先将要比较的两个list转换为set,再转回list就好了>>> l1 = [1, 2, 3, 4] >>> l2 = [2, 3, 5, 7] >>> list(set(l1) & set(l2)) [2, 3] >>> list(set(l1) | set(l2)) [1, 2, 3, 4, 5, 7] >>> list(set(l1) ^ set(l2)) [1, 4, 5, 7] 字典本质是键值对哈希表get用来获取某个键的值,不存在的话就用设置的default(默认为None)>>> d = dict(a=1, b=2) >>> d.get('a') 1 >>> d.get('c') >>> d.get('d', 2) 2 合并>>> d1 = {'a':1, 'b':2} >>> d2 = {'c':3, 'd':4} >>> nd = {**d1, **d2} >>> nd {'a': 1, 'b': 2, 'c': 3, 'd': 4} 相似的,列表也能够这样合并>>> l1 = [1, 2] >>> l2 = [3, 4] >>> l3 = [*l1, *l2] >>> l3 [1, 2, 3, 4] 键值对反转>>> kv = {'a': 1, 'b':2 , 'c': 3} >>> vk = zip(kv.values(), kv.keys()) >>> dict(vk) {1: 'a', 2: 'b', 3: 'c'} >>> min(vk) (1, 'a') >>> sorted(vk) [(1, 'a'), (2, 'b'), (3, 'c')] 键值排序>>> rows = [{k1: v1, k2: v2 ...}, ...] >>> from operator import itemgetter # 根据k1排序 >>> sorted(rows, key=itemgetter(k1)) # 相似的,对于class的对象能够用attrgetter进行排序 集合运算>>> a = {'a': 1, 'b': 2, 'c': 3} >>> b = {'x': 1, 'b': 2, 'c': 4} >>> a.keys() & b.keys() {'b', 'c'} >>> a.keys() - b.keys() {'a'} >>> a.items() & b.items() {('b', 2)} 其余数据结构具名元组经常使用于构建简单的类>>> from collections import namedtuple >>> Point = namedtuple('Point', ['x', 'y']) >>> p = Point(x=11, y=22) >>> p Point(x=11, y=22) >>> p.x + p.y 33 >>> coord = (33, 44) >>> q = Point(*coord) >>> q Point(x=33, y=44) 默认值字典经常使用于统计数目>>> from collections import defaultdict >>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C') >>> counts = defaultdict(int) >>> for word in words: ... counts[word] += 1 >>> counts defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1}) 双向队列>>> from collections import deque >>> q = deque(["Eric", "John", "Michael"]) >>> q.append("Terry") >>> q deque(['Eric', 'John', 'Michael', 'Terry']) >>> q.popleft() Eric' >>> q.pop() 'Terry' >>> q deque(['John', 'Michael']) 计数器>>> from collections import Counter >>> c = Counter('hello world') >>> c Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1}) >>> c.most_common(2) [('l', 3), ('o', 2)] 堆>>> import heapq >>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> c = list(heapq.merge(a, b)) >>> c [1, 2, 3, 4, 5, 6] >>> heapq.nlargest(3, c) [6, 5, 4] >>> heapq.nsmallest(3, c) [1, 2, 3] OOP只读属性能够经过在变量名前加__来使其变成私有变量,外部没法直接访问,但能够经过类定义的方法来访问。class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name def set_name(self, name): self.__name = name >>> p = Person('alphardex') >>> p.name Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Person' object has no attribute 'name' >>> p.get_name() 'alphardex' >>> p.set_name('wang') >>> p.get_name() 'wang' @property确定有的人不习惯经过方法来访问私有变量,那么如何用属性来访问私有变量呢?这时就要用到@property了,它能够把一个方法变成属性调用class Person(object): def __init__(self, name): self.__name = name @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value >>> p = Person('alphardex') >>> p.name 'alphardex' >>> p.name = 'wang' >>> p.name 'wang' slots当咱们定义了一个class并用其建立了一个实例后,能够动态地给其绑定属性,若是要限制这一点,能够利用__slots__class Person(object): __slots__ = ('name', 'age') >>> p = Person('wang') >>> p.name = 'wang' >>> p.age = 21 >>> p.skill = 'Python' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Person' object has no attribute 'skill' 魔术方法魔术方法能够用来定制类的功能。好比__repr__用来调试时打印类的字符串class Person(object): def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f'<Person {self.name} age: {self.age}>' >>> p = Person('alphardex', 21) >>> p <Person alphardex age: 21> 想了解更多魔术方法请参见官方文档元类type俗话说道生一,一辈子二,二生三,三生万物。在Python里能够这么说:type生元类,元类生类,类生实例。用一个数字变量的建立来讲明这一点吧>>> age = 21 >>> age.__class__ <class 'int'> >>> age.__class__.__class__ <class 'type'> age能够看做为int类的实例,而int类又能够看作type类的实例。也就是说,type建立了int类,实际上诸如str和bool等类也是由type建立的。>>> help(type) Help on class type in module builtins: class type(object) | type(object_or_name, bases, dict) | type(object) -> the object's type | type(name, bases, dict) -> a new type def say_hello(self, name='world'): print(f'Hello, {name}') >>> Hello = type('Hello', (object,), dict(hello=say_hello)) >>> h = Hello() >>> type(Hello) <class 'type'> >>> type(h) <class '__main__.Hello'> 经过用help查看type,能够发现它确实能动态地建立类:第一个参数是类名name,第二个参数是基类bases,第三个参数是dict,里面包含着类的全部方法。实际上,type是Python的一个内置元类。自定义元类固然,你也能够利用type来定义本身的元类。class JSArrayMeta(type): def __new__(cls, name, bases, attrs): attrs['push'] = lambda self, value: self.append(value) attrs['shift'] = lambda self: self.pop(0) attrs['includes'] = lambda self, value: value in self return type.__new__(cls, name, bases, attrs) class JSList(list, metaclass=JSArrayMeta): def __init__(self, value): self.extend(value) >>> l = JSList([1, 2, 3]) >>> l [1, 2, 3] >>> l.push('a') >>> l [1, 2, 3, 'a'] >>> l.shift() 1 >>> l [2, 3, 'a'] >>> l.includes(3) True 咱们首先定制了一个元类,叫JSArrayMetaclass(没错就是JS里的数组XD)注意元类的命名规则:结尾必定要有Meta做为识别__new__方法用来建立JSList类,它接受4个参数JSList继承了list类,同时得到了元类的全部方法其余加载内置模块利用-m参数,咱们能够直接加载Python的模块# 搭建http服务器 $ python -m http.server # 建立虚拟环境 $ python -m venv <name> # 性能测试 $ python -m cProfile <file.py> # 查看JSON $ cat <file.json> | python -m json.tool 数据序列化import pickle data = ... # Some Python object # 存储 with open(f'{file}.pickle', 'wb') as f: pickle.dump(data, f) # 读取 with open(f'{file}.pickle', 'rb') as f: data = pickle.load(f) 数据分析利用pandas模块能够对数据进行分析$ pip install pandas >>> import pandas as pd >>> data = pd.read_csv(...) # 数据查看 >>> data.columns # 查看数据结构 >>> data.describe() # 简要数据分析 >>> data.sort_values(by=...) # 对数据排序 # 数据选取 >>> data.head() # 查看前五条数据 >>> data.iloc[n] # 选择位置为n的数据,支持切片 >>> data[data.A > 0] # 选择A栏大于0的数据 >>> data[data.B.isin([...])] # 利用in过滤数据 >>> data[~data.B.isin([...])] # 上一句的取反,至关于not in # 缺失值处理 >>> pd.isna(data) # 获取缺失值的布尔标记 >>> data.dropna(how='any') # 去除全部含有缺失值的栏 >>> data.fillna(value=5) # 填充全部含有缺失值的栏 # 数据保存(能够相互转换格式,支持excel、csv和json) >>> data.to_json(...)
Pythonic,简言之就是以Python这门语言独特的方式写出既简洁又优美的代码!笔者精心整理了许多实用的Python tricks,想要提升效率、写出高质量的Python代码的话此文必看。 html
注:请将Python更新到3.6版,方能完美运行本文的全部代码。java
在字符串前加f,就能够在里面用大括号嵌入变量了(能够代替format函数)python
>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'
>>> text = ['I', ' Love ', 'Python!']
>>> print(''.join(text))
I Love Python!
>>> 'ov' in 'love'
True
>>> 'Love'[::-1]
'evoL'
>>> for e in reversed([1,3,5]): print(e)
5 3 1
保存文件时,咱们必须去除一些非法字符串,此处利用any函数实现mysql
def rectify(name):
if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]):
name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]])
return name
>>> import html
>>> html.unescape('<')
'<'
>>> html.escape('<')
'<'
*args:任意数量的位置参数,可被打包成元组。
**kwargs:任意数量的关键词参数,可被打包成字典。sql
def foo(*args, **kwargs):
print(f"args: {args}")
print(f"kwargs: {kwargs}")
>>> foo(1,2,3,4, a=1,b=2,c=3)
args: (1, 2, 3, 4)
kwargs: {'a': 1, 'b': 2, 'c': 3}
def foo(x, y):
print(x, y)
alist = [1, 2]
adict = {'x': 1, 'y': 2}
>>> foo(*alist)
1, 2
>>> foo(**adict)
1, 2
装饰器的主要用途:打印日志、检测性能、数据库事务、URL路由
它本质上就是一个高阶函数,它接收一个函数做为参数,而后,返回一个新函数。
想理解装饰器,就得知道如下两点:
1. 函数皆对象
2. 闭包特性(内函数能捕捉到外函数的环境变量)数据库
from datetime import datetime
import functools
def log(f):
@functools.wraps(f)
def wr(*args, **kwargs):
print(f'call {f.__name__}() at {datetime.now()}')
return f(*args, **kwargs)
return wr
@log
def square(x):
return x ** 2
>>> square(2)
call square() at 2018-01-24 11:01:19.547516
4
注意到为了让@deco自适应任何参数定义的函数,咱们将可变参数args, *kwargs做为了wr的参数json
为了防止wr的函数属性覆盖掉原函数的属性,咱们必须利用@functools.wraps(f)来把原函数的全部属性复制到新函数里数组
# 不加@functools.wraps(f)的状况下
>>> square.__name__
'wr'
# 加了@functools.wraps(f)的状况下
>>> square.__name__
'square'
若是想给装饰器传递参数,那么你必须利用闭包特性再嵌套一层函数,不过这并不经常使用。安全
def perf(f):
@functools.wraps(f)
def wr(*args, **kwargs):
start = time.time()
r = f(*args, **kwargs)
end = time.time()
print(f'call {f.__name__}() in {end - start}')
return r
return wr
@perf
def test(x):
time.sleep(2)
return x
>>> test(5)
call test() in 2.0007083415985107
5
def link_mysql(fun):
def wr(*args, **kwargs):
with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur:
fun(cur, *args, **kwargs)
return wr
@link_mysql
def insert_data(cur, ...):
# execute your sql here.
文件操做(超经常使用)、进程互斥锁和支持上下文的其余对象
目的是为了代替try语句和简化语法
以文件操做为例:利用它,文件会自动打开和关闭ruby
with open('/path/to/file', 'r') as f:
handle_f
上下文语句支持嵌套(nested)
例如将a文件的源数据写入b文件里:
with open('a.txt') as i, open('b.txt') as o:
o.write(i.read())
经过上下文管理协议__enter__和__exit__来实现
Python有个库contextlib利用生成器简化了这种实现,如下是大致框架
from contextlib import contextmanager
@contextmanager
def make_context() :
# enter
try:
yield <value>
except Exception as e:
# handle_err
finally:
# exit
with make_context() as <value>:
# handle_value
如下是with语句操做文件的实质
因为自定义,函数名用my_open,但功能和open几乎同样
@contextmanager
def my_open(filename, mode):
f = open(filename, mode)
try:
yield f
except Exception as e:
raise e
finally:
f.close()
with my_open('/path/to/file', 'r') as f:
handle_f
partial()用于把一个函数的某些参数给固定住(也就是设置默认值),并返回一个新的函数。
def int2(x, base=2):
return int(x, base)
至关于:
import functools
int2 = functools.partial(int, base=2)
元组是一个immutable对象,有如下重要性:
- 性能优化
- 线程安全
- 能够做为dict的key(hashable)
- 拆包特性
a, b = b, a
两个数字交换的原理就是它。
如下是利用它来获取文件名及其扩展名
>>> import os
>>> filename, ext = os.path.splitext('patch.exe')
>>> filename
'patch'
>>> ext
'exe'
更多的解包方式(_表明舍弃,*表明可变长元组)
>>> t = (1, 2, 3, 4)
>>> first, *middle, last = t
>>> middle
[2, 3]
>>> _, *rest = t
>>> rest
[2, 3, 4]
若是想要获取列表的多个元素,就得用到切片
list[start:stop:step]
你甚至能够给切片命名,加强复用性和可读性:
s = slice(start,stop,step)
list[s]
切片的原理是序列协议
class Seq:
def __getitem__(self, index):
return index
>>> s = Seq()
>>> s[1:5:2]
slice(1, 5, 2)
以上实现的是不可变序列协议,若是可变的话还要添加__setitem__()
若是在运行时添加协议的话也行,这叫猴子补丁
>>> def set_item(self, key, value):
self[key] = value
>>> classname.__setitem__ = set_item
这是Python最强大的几个特征之一。
格式也很简单,其中if条件能够省略,for循环能够有多个
[i for i in iterable if condition]
10-20全部偶数的平方:
[i*i for i in range(10, 21) if i % 2 == 0 ]
一行实现快排
def qsort(arr):
return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
enumerate()能够把一个list变成索引-元素对。
for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
0 A 1 B 2 C
zip()能够将可迭代的对象做为参数,将对象中对应的元素打包成一个个元组,并返回一个迭代器,经常使用于同时遍历两个可迭代对象。
>>> li1 = ['Python' ,'JavaScript', 'Java']
>>> li2 = [1, 2, 3]
>>> nl = zip(li1, li2)
<zip object at memory>
>>> list(nl)
[('Python', 1), ('JavaScript', 2), ('Java', 3)]
配合dict能够生成字典
>>> l1 = ['A', 'B', 'C']
>>> l2 = [1, 2, 3]
>>> dict(zip(l1, l2))
{'A': 1, 'B': 2, 'C': 3}
>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> x
[1, 2, 3, 4, 5]
>>> x.append([6, 7])
>>> x
[1, 2, 3, 4, 5, [6, 7]]
首先将要比较的两个list转换为set,再转回list就好了
>>> l1 = [1, 2, 3, 4]
>>> l2 = [2, 3, 5, 7]
>>> list(set(l1) & set(l2))
[2, 3]
>>> list(set(l1) | set(l2))
[1, 2, 3, 4, 5, 7]
>>> list(set(l1) ^ set(l2))
[1, 4, 5, 7]
本质是键值对哈希表
用来获取某个键的值,不存在的话就用设置的default(默认为None)
>>> d = dict(a=1, b=2)
>>> d.get('a')
1
>>> d.get('c')
>>> d.get('d', 2)
2
>>> d1 = {'a':1, 'b':2}
>>> d2 = {'c':3, 'd':4}
>>> nd = {**d1, **d2}
>>> nd
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
相似的,列表也能够这样合并
>>> l1 = [1, 2]
>>> l2 = [3, 4]
>>> l3 = [*l1, *l2]
>>> l3
[1, 2, 3, 4]
>>> kv = {'a': 1, 'b':2 , 'c': 3}
>>> vk = zip(kv.values(), kv.keys())
>>> dict(vk)
{1: 'a', 2: 'b', 3: 'c'}
>>> min(vk)
(1, 'a')
>>> sorted(vk)
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> rows = [{k1: v1, k2: v2 ...}, ...]
>>> from operator import itemgetter
# 根据k1排序
>>> sorted(rows, key=itemgetter(k1))
# 相似的,对于class的对象能够用attrgetter进行排序
>>> a = {'a': 1, 'b': 2, 'c': 3}
>>> b = {'x': 1, 'b': 2, 'c': 4}
>>> a.keys() & b.keys()
{'b', 'c'}
>>> a.keys() - b.keys()
{'a'}
>>> a.items() & b.items()
{('b', 2)}
经常使用于构建简单的类
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(x=11, y=22)
>>> p
Point(x=11, y=22)
>>> p.x + p.y
33
>>> coord = (33, 44)
>>> q = Point(*coord)
>>> q
Point(x=33, y=44)
经常使用于统计数目
>>> from collections import defaultdict
>>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C')
>>> counts = defaultdict(int)
>>> for word in words:
... counts[word] += 1
>>> counts
defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1})
>>> from collections import deque
>>> q = deque(["Eric", "John", "Michael"])
>>> q.append("Terry")
>>> q
deque(['Eric', 'John', 'Michael', 'Terry'])
>>> q.popleft()
Eric'
>>> q.pop()
'Terry'
>>> q
deque(['John', 'Michael'])
>>> from collections import Counter
>>> c = Counter('hello world')
>>> c
Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
>>> c.most_common(2)
[('l', 3), ('o', 2)]
>>> import heapq
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = list(heapq.merge(a, b))
>>> c
[1, 2, 3, 4, 5, 6]
>>> heapq.nlargest(3, c)
[6, 5, 4]
>>> heapq.nsmallest(3, c)
[1, 2, 3]
能够经过在变量名前加__来使其变成私有变量,外部没法直接访问,但能够经过类定义的方法来访问。
class Person(object):
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
>>> p = Person('alphardex')
>>> p.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'name'
>>> p.get_name()
'alphardex'
>>> p.set_name('wang')
>>> p.get_name()
'wang'
确定有的人不习惯经过方法来访问私有变量,那么如何用属性来访问私有变量呢?这时就要用到@property了,它能够把一个方法变成属性调用
class Person(object):
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
self.__name = value
>>> p = Person('alphardex')
>>> p.name
'alphardex'
>>> p.name = 'wang'
>>> p.name
'wang'
当咱们定义了一个class并用其建立了一个实例后,能够动态地给其绑定属性,若是要限制这一点,能够利用__slots__
class Person(object):
__slots__ = ('name', 'age')
>>> p = Person('wang')
>>> p.name = 'wang'
>>> p.age = 21
>>> p.skill = 'Python'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'skill'
魔术方法能够用来定制类的功能。
好比__repr__用来调试时打印类的字符串
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'<Person {self.name} age: {self.age}>'
>>> p = Person('alphardex', 21)
>>> p
<Person alphardex age: 21>
想了解更多魔术方法请参见官方文档
俗话说道生一,一辈子二,二生三,三生万物。
在Python里能够这么说:type生元类,元类生类,类生实例。
用一个数字变量的建立来讲明这一点吧
>>> age = 21
>>> age.__class__
<class 'int'>
>>> age.__class__.__class__
<class 'type'>
age能够看做为int类的实例,而int类又能够看作type类的实例。
也就是说,type建立了int类,实际上诸如str和bool等类也是由type建立的。
>>> help(type)
Help on class type in module builtins:
class type(object)
| type(object_or_name, bases, dict)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
def say_hello(self, name='world'):
print(f'Hello, {name}')
>>> Hello = type('Hello', (object,), dict(hello=say_hello))
>>> h = Hello()
>>> type(Hello)
<class 'type'>
>>> type(h)
<class '__main__.Hello'>
经过用help查看type,能够发现它确实能动态地建立类:第一个参数是类名name,第二个参数是基类bases,第三个参数是dict,里面包含着类的全部方法。
实际上,type是Python的一个内置元类。
固然,你也能够利用type来定义本身的元类。
class JSArrayMeta(type):
def __new__(cls, name, bases, attrs):
attrs['push'] = lambda self, value: self.append(value)
attrs['shift'] = lambda self: self.pop(0)
attrs['includes'] = lambda self, value: value in self
return type.__new__(cls, name, bases, attrs)
class JSList(list, metaclass=JSArrayMeta):
def __init__(self, value):
self.extend(value)
>>> l = JSList([1, 2, 3])
>>> l
[1, 2, 3]
>>> l.push('a')
>>> l
[1, 2, 3, 'a']
>>> l.shift()
1
>>> l
[2, 3, 'a']
>>> l.includes(3)
True
利用-m参数,咱们能够直接加载Python的模块
# 搭建http服务器
$ python -m http.server
# 建立虚拟环境
$ python -m venv <name>
# 性能测试
$ python -m cProfile <file.py>
# 查看JSON
$ cat <file.json> | python -m json.tool
import pickle
data = ... # Some Python object
# 存储
with open(f'{file}.pickle', 'wb') as f:
pickle.dump(data, f)
# 读取
with open(f'{file}.pickle', 'rb') as f:
data = pickle.load(f)
利用pandas模块能够对数据进行分析
$ pip install pandas
>>> import pandas as pd
>>> data = pd.read_csv(...)
# 数据查看
>>> data.columns # 查看数据结构
>>> data.describe() # 简要数据分析
>>> data.sort_values(by=...) # 对数据排序
# 数据选取
>>> data.head() # 查看前五条数据
>>> data.iloc[n] # 选择位置为n的数据,支持切片
>>> data[data.A > 0] # 选择A栏大于0的数据
>>> data[data.B.isin([...])] # 利用in过滤数据
>>> data[~data.B.isin([...])] # 上一句的取反,至关于not in
# 缺失值处理
>>> pd.isna(data) # 获取缺失值的布尔标记
>>> data.dropna(how='any') # 去除全部含有缺失值的栏
>>> data.fillna(value=5) # 填充全部含有缺失值的栏
# 数据保存(能够相互转换格式,支持excel、csv和json)
>>> data.to_json(...)