社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python进阶之道

alphardex • 6 年前 • 493 次点击  
阅读 29

Python进阶之道

repo:github.com/alphardex/p…

如果说优雅也有缺点的话,那就是你需要艰巨的工作才能得到它,需要良好的教育才能欣赏它。 —— Edsger Wybe Dijkstra

笔者精心整理了许多实用的Python tricks,欢迎各位Pythonistia参考。

基本

f-string

name = 'alphardex'
f'Ore wa {name} desu, {4 * 6} sai, gakusei desu.'
# 'Ore wa alphardex desu, 24 sai, gakusei desu.'
复制代码

三元运算符

# if condition:
#    fuck
# else:
#    shit
fuck if condition else shit
复制代码

字符串的拼接,反转与分割

letters = ['h', 'e', 'l', 'l', 'o']
''.join(letters)
# 'hello'
letters.reverse()
# ["o", "l", "l", "e", "h"]
name = 'nameless god'
name.split(' ')
# ['nameless', 'god']
复制代码

判断元素的存在性

'fuck' in 'fuck you'
# True
'slut' in ['bitch', 'whore']
# False
'company' in {'title': 'SAO III', 'company': 'A1 Pictures'}
# True
复制代码

函数

匿名函数

类似ES6的箭头函数,函数的简化写法,配合map、filter、sorted等高阶函数食用更佳

注:在Python中,一般更倾向于用列表推导式来替代map和filter

# def foo(parameters):
#     return expression
foo = lambda parameters: expression
复制代码

map - 映射

numbers = [1, 2, 3, 4, 5]
list(map(lambda e: e ** 2, numbers))
# [1, 4, 9, 16, 25]
复制代码

filter - 过滤

values = [None, 0, '', True, 'alphardex', 666]
list(filter(lambda e:e, values))
# [True, "alphardex", 666]
复制代码

sort - 排序

tuples = [(1, 'kirito'), (2, 'asuna'), (4, 'alice'), (3, 'eugeo')]
sorted(tuples, key=lambda x: x[1])
# [(4, 'alice'), (2, 'asuna'), (3, 'eugeo'), (1, 'kirito')]
sorted(tuples, key=lambda x: x[1], reverse=True)
# [(1, 'kirito'), (3, 'eugeo'), (2, 'asuna'), (4, 'alice')]
tuples.sort()
tuples
# [(1, 'kirito'), (2, 'asuna'), (3, 'eugeo'), (4, 'alice')]
复制代码

其中,key这个参数接受一个函数,并将其运用在序列里的每一个元素上,所产生的结果将是排序算法依赖的对比关键字

在这个例子中,key里面的函数获取了每个元素的字符串,排序算法将会基于字母顺序进行排序

排序默认是升序,把reverse设置为True,就能按降序排序

sorted会新建一个列表作为返回值,而list.sort则是就地排序

其他骚操作

from functools import reduce
# 求1到100的积
reduce(lambda x, y: x * y, range(1, 101))
# 求和就更简单了
sum(range(101))
# 5050
复制代码

扁平化列表

from functools import reduce
li = [[1,2,3],[4,5,6], [7], [8,9]]
flatten = lambda li: [item for sublist in li for item in sublist]
flatten(li)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 或者直接用more_itertools这个第三方模块
# from more_itertools import flatten
# list(flatten(li))
复制代码

星号和双星号

数据容器的合并

l1 = ['a', 'b']
l2 = [1, 2]
[*l1, *l2]
# ['a', 'b', 1, 2]
d1 = {'name': 'alphardex'}
d2 = {'age': 24}
{**d1, **d2}
# {'name': 'alphardex', 'age': 24}
复制代码

函数参数的打包与解包

# 打包


    

def foo(*args):
    print(args)
foo(1, 2)
# (1, 2)

def bar(**kwargs):
    print(kwargs)
bar(name='alphardex', age=24)
# {'name': 'alphardex', 'age': 24}

# 解包
t = (10, 3)
quotient, remainder = divmod(*t)
quotient
# 商:3
remainder
# 余:1
复制代码

数据容器

列表

推导式

笔者最爱的语法糖:)

even = [i for i in range(10) if not i % 2]
even
# [0, 2, 4, 6, 8]
复制代码

同时迭代元素与其索引

用enumerate即可

li = ['a', 'b', 'c']
print([f'{i+1}. {elem}' for i, elem in enumerate(li)])
# ['1. a', '2. b', '3. c']
复制代码

元素的追加与连接

append在末尾追加元素,extend在末尾连接元素

li = [1, 2, 3]
li.append([4, 5])
li
# [1, 2, 3, [4, 5]]
li.extend([4, 5])
li
# [1, 2, 3, [4, 5], 4, 5]
复制代码

测试是否整体/部分满足条件

all测试所有元素是否都满足于某条件,any则是测试部分元素是否满足于某条件

all([e<20 for e in [1, 2, 3, 4, 5]])
# True
any([e%2==0 for e in [1, 3, 4, 5]])
# False
复制代码

同时迭代2个以上的可迭代对象

用zip即可

subjects = ('nino', 'miku', 'itsuki')
predicates = ('saikou', 'ore no yome', 'is sky')
print([f'{s} {p}' for s, p in zip(subjects, predicates)])
# ['nino saikou', 'miku ore no yome', 'itsuki is sky']
复制代码

去重

利用集合的互异性

li = [3, 1, 2, 1, 3, 4, 5, 6]
list(set(li))
# [1, 2, 3, 4, 5, 6]
# 如果要保留原先顺序的话用如下方法即可
sorted(set(li), key=li.index)
# [3, 1, 2, 4, 5, 6]
复制代码

解包

此法亦适用于元组等可迭代对象

最典型的例子就是2数交换

a, b = b, a
# 等价于 a, b = (b, a)
复制代码

用星号运算符解包可以获取剩余的元素

first, *rest = [1, 2, 3, 4]
first
# 1
rest
# [2, 3, 4]
复制代码

字典

遍历

d = {'name': "alphardex", 'age': 24}
[key for key in d.keys()]
# ['name', 'age']
[value for value in d.values()]
# ['alphardex', 24]
[f'{key}: {value}' for key, value in d.items()]
# ['name: alphardex', 'age: 24']
复制代码

排序

import operator
data = [{'rank': 2, 'author': 'alphardex'}, {'rank': 1, 'author': 'alphardesu'}]
data_by_rank = sorted(data, key=operator.itemgetter('rank'))
data_by_rank
# [{'rank': 1, 'author': 'alphardesu'}, {'rank': 2, 'author': 'alphardex'}]
data_by_rank_desc = sorted(data, key=lambda x: x['rank'], reverse=True)
# [{'rank': 2, 'author': 'alphardex'}, {'rank': 1, 'author': 'alphardesu'}]
复制代码

反转

d = {'name': 'alphardex', 'age': 24}
{v: k for k, v in d.items()}
# {'alphardex': 'name', 24: 'age'}
复制代码

缺失键处理

get返回键值,如果键不在字典中,将会返回一个默认值

d = {'name': 'alphardex', 'age': 24}
d.get('sex', 'male')
# male
复制代码

setdefault返回键值,如果键不在字典中,将会添加它并设置一个默认值

d = {'name': 'alphardex', 'age': 24}
# if 'sex' not in d:
#     d['sex'] = 'male'
d.setdefault('sex', 'male')
# male
d
# {'name': 'alphardex', 'age': 24, 'sex': 'male'}
复制代码

分组

from collections import defaultdict
people = [('alphardex', 'male'), ('koizumi moeka', 'female'), ('alphardesu', 'male'), ('satou hinata', 'female')]
gender_group = defaultdict(list)



    
for name, gender in people:
    gender_group[gender].append(name)
gender_group
# defaultdict(<class 'list'>, {'male': ['alphardex', 'alphardesu'], 'female': ['koizumi moeka', 'satou hinata']})
复制代码

实例化一个defaultdict时,通常要传入一个可调用对象(这里以list为例),它会在__getitem__找不到键时被调用,让__getitem__返回某种默认值

向字典插入数据,如果键(假设为new_key)不存在,则有以下三步:

  1. 调用list来新建一个列表
  2. 把这个新列表作为值,new_key作为它的键放到字典中
  3. 返回这个列表的引用

语言专属特性

下划线_的几层含义

repl中暂存结果

>>> 1 + 1
# 2
>>> _
# 2
复制代码

忽略某个变量

filename, _ = 'eroge.exe'.split('.')
filename
# 'eroge'
for _ in range(2):
    print('wakarimasu')
# wakarimasu
# wakarimasu
复制代码

i18n国际化

_("This sentence is going to be translated to other language.")
复制代码

增强数字的可读性

1_000_000
# 1000000
复制代码

上下文管理器

用于资源的获取与释放,以代替try-except语句

常用于文件IO,锁的获取与释放,数据库的连接与断开等

# try:
#     f = open(input_path)
#     data = f.read()
# finally:
#     f.close()
with open(input_path) as f:
    data = f.read()
复制代码

可以用@contextmanager来实现上下文管理器

from contextlib import contextmanager

@contextmanager
def open_write(filename):
    try:
        f = open(filename, 'w')
        yield f
    finally:
        f.close()

with open_write('onegai.txt') as f:
    f.write('Dagakotowaru!')
复制代码

静态类型注解

给函数参数添加类型,能提高代码的可读性和可靠性,大型项目的最佳实践之一

from typing import List

def greeting(name: str) -> str:
    return f'Hello {name}.'

def gathering(users: List[str]) -> str:
    return f"{', '.join(users)} are going to be raped."

print(greeting('alphardex'))
print(gathering(['Bitch', 'slut']))
复制代码

多重继承

在django中经常要处理类的多重继承的问题,这时就要用到super函数

如果单单认为super仅仅是“调用父类的方法”,那就错了

其实super指的是MRO中的下一个类,用来解决多重继承时父类的查找问题

MRO是啥?Method Resolution Order(方法解析顺序)

看完下面的例子,就会理解了

class A:
    def __init__(self):
        print('A')

class B(A):
    def __init__(self):
        print('enter B')
        super().__init__()
        print('leave B')

class C(A):
    def __init__(self):
        print('enter C')
        super().__init__()
        print('leave C')

class D(B, C):
    pass

d = D()
# enter B
# enter C
# A
# leave C
# leave B
print(d.__class__.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
复制代码

首先,因为D继承了B类,所以调用B类的__init__,打印了enter B

打印enter B后的super寻找MRO中的B的下一个类,也就是C类,并调用其__init__,打印enter C

打印enter C后的super寻找MRO中的C的下一个类,也就是A类,并调用其__init__,打印A

打印A后回到C的__init__,打印leave C

打印leave C后回到B的__init__,打印leave B

特殊方法

在django中,定义model的时候,希望admin能显示model的某个字段而不是XXX Object,那么就要定义好__str__

每当你使用一些内置函数时,都是在调用一些特殊方法,例如len()调用了__len__(), str()调用__str__()等

以下实现一个数学向量类,里面有6个特殊方法

from math import hypot

class Vector:
    # 实例创建
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    # 字符串表示形式
    def __repr__(self) -> str:
        return f'Vector({self.x}, {self.y})'

    # 数值转换 - 绝对值
    def __abs__(self) -> float:
        return hypot(self.x, self.y)

    # 数值转换 - 布尔值
    def __bool__(self) -> bool:
        return bool(abs(self))

    # 算术运算符 - 加
    def __add__(self, other: Vector) -> Vector:
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    # 算术运算符 - 乘
    def __mul__(self, scalar: float) -> Vector:
        return Vector(self.x * scalar, self.y * scalar)

v = Vector(3, 4)

# repr(v) => v.__repr__()
v
# Vector(3, 4)


    


# abs(v) => v.__abs__()
abs(v)
# 5.0

# bool(v) => v.__bool__()
bool(v)
# True

# v1 + v2  => v1.__add__(v2)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v1 + v2
# Vector(4, 6)

# v * 3  => v.__mul__(3)
v * 3
# Vector(9, 12)
复制代码

想了解所有的特殊方法可查阅官方文档,以下列举些常用的:

字符串表示形式:__str__, __repr__
数值转换:__abs__, __bool__, __int__, __float__, __hash__
集合模拟:__len__, __getitem__, __setitem__, __delitem__, __contains__
迭代枚举:__iter__, __reversed__, __next__
可调用模拟:__call__
实例创建与销毁:__init__, __del__
运算符相关:__add__, __iadd__, __mul__, __imul__
复制代码
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/32247
 
493 次点击