作者:半载流殇
链接: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('&lt')
'<'
>>> html.escape('<')
'&lt;'
函数可变参数*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 rreturn 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() :# entertry:yield <value>except Exception as e:# handle_errfinally:# exit

with make_context() as <value>:# handle_value
以下是with语句操作文件的实质由于自定义,函数名用my_open,但功能和open几乎一样@contextmanager
def my_open(filename, mode):f = open(filename, mode)try:yield fexcept Exception as e:raise efinally: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 = namedef get_name(self):return self.__namedef 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@propertydef name(self):return self.__name@name.setterdef 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 = nameself.age = agedef __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 typedef 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 selfreturn 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(...)

作者:半载流殇
链接: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('&lt')
'<'
>>> html.escape('<')
'&lt;'

函数

可变参数

*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 rreturn wr@perf
def test(x):time.sleep(2)return x>>> test(5)
call test() in 2.0007083415985107
5

数据库的cursor

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语句和简化语法
以文件操作为例:利用它,文件会自动打开和关闭

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() :# entertry:yield <value>except Exception as e:# handle_errfinally:# exitwith make_context() as <value>:# handle_value

以下是with语句操作文件的实质
由于自定义,函数名用my_open,但功能和open几乎一样

@contextmanager
def my_open(filename, mode):f = open(filename, mode)try:yield fexcept Exception as e:raise efinally: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

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}

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 = namedef get_name(self):return self.__namedef 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@propertydef name(self):return self.__name@name.setterdef 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 = nameself.age = agedef __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 typedef 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 selfreturn 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(...)

转载于:https://www.cnblogs.com/yezefei/p/8709039.html

Pythonic---------详细讲解相关推荐

  1. 适合新手练手,用Python爬取OPGG里英雄联盟英雄胜率及选取率,详细讲解加注释(建议收藏练手)

    今天来个简单的小项目,适合新手拿来练手,在OPGG上爬取英雄联盟里的法师,ADC,打野,辅助所有英雄的胜率及选取率,是不是感觉很高大上,但是却很简单,只要用三十多行代码就能实现,详细讲解每一行代码加注 ...

  2. Python的零基础超详细讲解(第十三天)-Python的类与对象

    基础篇往期文章如下: Python的零基础超详细讲解(第一天)-Python简介以及下载 Python的零基础超详细讲解(第二天)-Python的基础语法1 Python的零基础超详细讲解(第三天)- ...

  3. Python的零基础超详细讲解(第十二天)-Python函数及使用

    基础篇往期文章: Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博 ...

  4. Python的零基础超详细讲解(第七天)-Python的数据的应用

    往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...

  5. Python的零基础超详细讲解(第五天)-Python的运算符

    往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...

  6. java异常详细讲解_Java异常处理机制的详细讲解和使用技巧

    一起学习 1. 异常机制 1.1 异常机制是指当程序出现错误后,程序如何处理.具体来说,异常机制提供了程序退出的安全通道.当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器. 1.2 ...

  7. 未来网络发展的趋势——IPv6详细讲解与基本配置

    实验目的: 1. 掌握IPv6的基本工作原理: 2. 区别IPv6和IPv4有什么区别: 3. 掌握IPv6的一些新的特征: 4. 掌握IPv6的发展进程和部署情况: 实验拓扑: 实验步骤:   一. ...

  8. Php中如何记录本报时间,详细讲解PHP的日期时间函数date()

    详细讲解PHP的日期时间函数date() 作者:wang 日期:2009-06-06 字体大小: 小 中 大 1,年-月-日 echo date('Y-m-j'); 2007-02-6 echo da ...

  9. PE格式详细讲解4 - 系统篇04|解密系列

    PE格式详细讲解4 - 系统篇04 让编程改变世界 Change the world by program   到此为止,小甲鱼和大家已经学了许多关于 DOS header 和 PE header 的 ...

  10. python爬虫原理-python爬虫原理详细讲解

    原标题:python爬虫原理详细讲解 一 .爬虫是什么 1.什么是互联网? 互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,像一张网一样. 2.互联网建立的目的?互联网的 ...

最新文章

  1. [文档].Altera – SOPC Builder组件开发攻略
  2. 网络协议基础:ARP简析
  3. BP: 通过SAP name拿到central person id
  4. 【计算机网络】三次握手与四次挥手
  5. QMake Automatic Dependencies
  6. C++中关于隐藏的理解
  7. python重命名csv文件_Python根据文件中选定的字符复制和重命名许多小csv文件
  8. WCF Transaction
  9. Xcode 5中缺少Provisioning Profiles菜单项
  10. GMQ区块链生态系统平行链,未来将应用于众多产业
  11. 获取QQ音乐排行榜数据
  12. 13丨性能测试场景:如何进行场景设计
  13. WPF实现拍照截图功能(WPFMediaKit 调用摄像头和拍照)
  14. android--------Android Studio常见问题以及解决方式
  15. DBeaver与excel
  16. python自然语言分析_Python自然语言用金庸的武侠小说做分析和处理
  17. 【广度优先搜索-中等】1905. 统计子岛屿
  18. es like and or_广东生态所孙蔚旻团队ESamp;T发表利用稳定同位素示踪宏基因组分箱联用技术揭示砷污染土壤中的厌氧砷氧化微生物及其代谢途径...
  19. 水平滚动条和垂直滚动条设置
  20. java技术--电话语音通知

热门文章

  1. 修改mysql编码方式centos_CentOS下修改mysql数据库编码为UTF-8(附mysql开启远程链接和开放3306端口)...
  2. 华为杯大学生计算机软件大赛,关于举办2018年西安电子科技大学程序设计网络赛暨第十六届“华为杯”大学生程序设计竞赛的通知...
  3. python超市售货统计程序_用Python实现简易超市售货系统
  4. android项目编码规范,Android 项目规范
  5. 操作系统上机作业--实现mysys(多进程)
  6. math.sqrt 有问题_JavaScript中带有示例的Math.SQRT2属性
  7. 如何在Python中针对一个值检查多个变量?
  8. c# sizeof_C#程序演示sizeof()运算符的示例
  9. 递归下降语法分析器的构建_一文了解函数式查询优化器Spark SQL Catalyst
  10. php打印出函数的内容吗,PHP打印函数集合详解以及PHP打印函数对比详解(精)