本文将介绍15个简洁的Python技巧,向着简洁更高效,学习易懂出发。
假设要对以下字典列表进行排序:
people = [
{<!-- --> 'name': 'John', "age": 64 },
{<!-- --> 'name': 'Janet', "age": 34 },
{<!-- --> 'name': 'Ed', "age": 24 },
{<!-- --> 'name': 'Sara', "age": 64 },
{<!-- --> 'name': 'John', "age": 32 },
{<!-- --> 'name': 'Jane', "age": 34 },
{<!-- --> 'name': 'John', "age": 99 },
]
不仅要按名字或年龄对其进行排序,还要将两个字段同时进行排序。在SQL中,会是这样的查询:
SELECT * FROM people ORDER by name, age
实际上,这个问题的解决方法可以非常简单,Python保证sort函数提供了稳定的排序顺序,这也意味着比较相似的项将保留其原始顺序。要实现按名字和年龄排序,可以这样做:
import operator
people.sort(key=operator.itemgetter('age'))
people.sort(key=operator.itemgetter('name'))
要注意如何反转顺序。首先按年龄分类,然后按名字分类,使用operator.itemgetter()从列表中的每个字典中获取年龄和名字字段,这样你就会得到想要的结果:
[
{<!-- -->'name': 'Ed', 'age': 24},
{<!-- -->'name': 'Jane', 'age': 34},
{<!-- -->'name': 'Janet','age': 34},
{<!-- -->'name': 'John', 'age': 32},
{<!-- -->'name': 'John', 'age': 64},
{<!-- -->'name': 'John', 'age': 99},
{<!-- -->'name': 'Sara', 'age': 64}
]
名字是主要排序项,如果姓名相同,则以年龄排序。因此,所有John都按年龄分组在一起。
自3.7版之后,Python开始能提供数据类别。比起常规类或其他替代方法(如返回多个值或字典),它有着更多优点:
from dataclasses import dataclass
@dataclass
classCard:
rank: str
suit: str
card=Card("Q", "hearts")
print(card == card)
# True
print(card.rank)
# 'Q'
print(card)
Card(rank='Q', suit='hearts')
列表推导可以在列表填写里代替讨厌的循环,其基本语法为
[ expression for item in list if conditional ]
来看一个非常基本的示例,用数字序列填充列表:
mylist = [i for i inrange(10)]
print(mylist)
# [0, 1, 2, 3,4, 5, 6, 7, 8, 9]
因为可以使用表达式,所以你还可以进行一些数学运算:
squares = [x**2for x inrange(10)]
print(squares)
# [0, 1, 4, 9,16, 25, 36, 49, 64, 81]
甚至能调用外部函数:
defsome_function(a):
return (a +5) /2
my_formula= [some_function(i) for i inrange(10)]
print(my_formula)
# [2.5, 3.0,3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0]
最后,可以使用if函数来筛选列表。在这种情况下,只保留可被2除的值:
filtered = [i for i inrange(20) if i%2==0]
print(filtered)
# [0, 2, 4, 6,8, 10, 12, 14, 16, 18]
使用sys.getsizeof()可以检查对象的内存使用情况:
import sys
mylist =range(0, 10000)
print(sys.getsizeof(mylist))
# 48
为什么这个庞大的列表只有48个字节呢,这是因为range函数返回的类表现为列表。与使用实际的数字列表相比,数序列的存储效率要高得多。我们可以通过列表推导来创建相同范围内的实际数字列表:
import sys
myreallist = [x for x inrange(0, 10000)]
print(sys.getsizeof(myreallist))
# 87632
通过使用sys.getsizeof(),我们可以了解更多关于Python和内存使用情况的信息。
要查找列表或字符串中最频繁出现的值:
test = [1, 2, 3, 4, 2, 2, 3, 1, 4, 4, 4]
print(max(set(test), key = test.count))
# 4
还有一种更有效的方法:
from collections import Counter
Counter(test).most_common(1)
# [4: 4]
你可以使用attrs代替数据类,选择attrs有两个原因:
@attrs
classPerson(object):
name =attrib(default='John')
surname =attrib(default='Doe')
age =attrib(init=False)
p =Person()
print(p)
p=Person('Bill', 'Gates')
p.age=60
print(p)
# Output:
# Person(name='John', surname='Doe',age=NOTHING)
# Person(name='Bill', surname='Gates', age=60)
实际上,attrs的作者已经在使用引入数据类的PEP了。数据类被有意地保持得更简单、更容易理解,而attrs 提供了可能需要的所有特性。
dict1 = {<!-- --> 'a': 1, 'b': 2 }
dict2= {<!-- --> 'b': 3, 'c': 4 }
merged= {<!-- --> **dict1, **dict2 }
print (merged)
# {'a': 1, 'b':3, 'c': 4}
如果有重叠的键,第一个字典中的键将被覆盖。在Python 3.9中,合并字典变得更加简洁。上面Python 3.9中的合并可以重写为:
merged = dict1 | dict2
Python中的函数在没有字典,列表和类的情况下可以返回多个变量,它的工作方式如下:
defget_user(id):
# fetch user from database
# ....
return name, birthdate
name, birthdate =get_user(4)
这是有限的返回值,但任何超过3个值的内容都应放入一个(数据)类。
filter()函数接受2个参数:
首先我们创建1个列表,并且剔除掉小于等于3的元素:
original_list = [ 1,2,3,4,5]#定义列表
#定义过滤函数
4 def filter_three(number):5
return number > 3
filtered = filter(filter_three, original_list)
filtered_list = list(filtered)
filtered_list
#[4,5]
我们定义了列表original_list接着我们定义了一个接受数值型参数number的函数filter_three,当传入的参数值大于3时会返回True,反之则会返回False我们定义了filter对象filtered,其中filter()接受的第一个参数是函数对象,第二个参数是列表对象最终我们将filter对象转化为列表,最终得到经filter_three过滤后original_list内留下的元素。
类似的,我们也可以利用列表推导式来过滤列表元素,作为一种生成和修改列表优雅的方式,下面是使用列表推导完成同样任务的过程:
original_list = [1,2,3,4,5]2
filtered_list = [ number for number in original_list if number > 3]#在列表推导过程中引入条件判断
print(filtered_list)
#[4,5]
Python中内置的map()函数使得我们可以将某个函数应用到可迭代对象内每一个元素之上。
比方说我们想获取到一个列表对象中每一个元素的平方,就可以使用到map()函数,就像下面的例子一样:
original_list = [1,2,3,4,5]
def square( number):
return number **2
squares =map(square, original_list)
squares_list = list( squares)
print(squares_list)
#[1,4,9,16,25]
类似filter()的工作过程,下面我们来看看发生了什么:
首先我们定义了列表original_list,以及接受数值型参数并返回其平方值的函数square()接着我们定义了map对象squares,类似filter(),map()接受的第一个参数是函数对象,第二个参数是列表对象最终我们将map对象squares列表化,就得到了想要的结果。
同样的我们也可以使用列表推导式完成同样的任务:
original_list = [1,2,3,4,5]
squares_list = [number ** 2for number in original_list]
print(squares_list)
#[1,4,9, 16,25]
有些情况下我们需要将两个或以上数量的列表组合在一起,这类需求使用zip()来完成非常方便。zip()函数接收多个列表作为参数传入,进而得到每个位置上一一对应的元素组合,就像下面的例子一样:
numbers = [ 1,2,3]
letters = [ 'a', 'b', 'c']
combined = zip(numbers,letters)
combined_list = list( combined)
print(combined_list)
for item in zip( numbers,letters ):
print(item[0], '\t', item[1])
#[(1,'a'),(2,'b'),(3, 'c')]
#1 a
#2 b
#3 c
Python中的列表是有序的数据结构,正因如此,列表中元素的顺序很重要,有些时候我们需要翻转列表中所有元素的顺序,可以通过Python中的切片操作,用::-1来快捷地实现:
original_list = [1,2,3,4,5]
reversed_list = original_list[ : : -1]
print('翻转前: ', original_list)
print('翻转后:', reversed_list)
#翻转前:[ 1,2,3,4,5]
#翻转后:[5,4,3,2,1]
有些情况下我们想要检查列表中是否存在某个元素,这种时候就可以使用到Python中的in运算符,譬如说我们有一个记录了所有比赛获胜队伍名称的列表,当我们想查询某个队名是否已获胜时,可以像下面的例子一样:
games = [ 'Yankees ', 'Yankees ', 'Cubs ', 'Blue Jays ', 'Giants ']
def isin(item,list_name) :
if item in list_name: print(f"{<!-- -->item} is in the list! ")
else: print(f"{<!-- -->item} is not in the list! ")
isin( 'Blue Jays ' , games)
isin( ' Angels', games)
#Blue Jays is in the list!
#Angels is not in the list!
有些情况下我们会遇到一些嵌套的列表,其每个元素又是各自不同的列表,这种时候我们就可以利用列表推导式来把这种嵌套列表展平,如下面2层嵌套的例子:
nested_list = [[1,2,3],[4,5,6],[7,8,9]]
flat_list = [i for j in nested_list for i in j]
print(flat_list)
#[1,2,3,4,5,6,7,8,9]
额外补充:
这里只考虑到两层嵌套的列表,如果是更多层嵌套,就需要有多少层写多少for循环,比较麻烦,其实还有一种更好的方法,我们可以使用pip install dm-tree来安装tree这个专门用于展平嵌套结构的库,可以展平任意层嵌套列表,使用例子如下:
import tree
nested_list_2d = [[1,2,3],[4,5,6],[7,8,9]]
nested_list_3d = [[[1,2],[3,4]],
[[5,6],[7,8]],
[[9,10],[11,12]]]
print(tree.flatten(nested_list_2d))
print(tree.flatten(nested_list_3d))
#[1,2,3,4,5,6,7,8,9]
#[1,2,3,4,5,6,7,,8, 9, 10, 11,12]
如果你想要查看列表中的值是否都是唯一值,可以使用Python中的set数据结构的特点,譬如下面的例子:
list1 = [ 1,2,3,4,5]
list2 = [1,1,2,3,4]
def isunique( 1):
if len(l) == len(set(l)) :
print( 唯一! ')
eise: print(('不唯—! ')
isunique( list1)
isunique(list2)
#唯—!
#不唯—!