2 Python学习记录-容器类型

python常见的容器类型有: 列表,元组,字典,集合

列表list:存放多个不同类型的对象

元组tuple:初始化之后就不可修改的list

字典dict: key-value类型的数据

集合set:不可重复列表的

1、遍历的时候获取下标

循环遍历的时候,会逐个拿到成员,但是有时候想同时获得下标,可以选择内置的函数

enumerate() 实现,   enumerate() 适用于任何 可迭代对象,列表,元组,字符串等。

names = ['jerry', 'tome']
for index, value in enumerate(names):
    print(index, value)

2、列表推导式

处理某个列表的需求:1、修改某些值 2、剔除某些值 ,然后产生一个新的列表。

可以采用列表推导式:写法比较简单,类似filter,然后做处理

>>> numbers = [1,2,3,4,5]
>>> result = [n * 100 for n in numbers if n % 2 == 0]
>>> result
[200, 400] 

3、列表可变性

python内置类型分为可变和不可变:

可变:列表,字典,集合

不可变:整数 浮点数  字符串  字节串  元组

 3.1 字符串添加内容

orgin_str = "abc"

def add_str(in_str):
    print(f"receive: {in_str}")
    in_str += " add"
    print(f"add after: {in_str}")

print(orgin_str)
add_str(orgin_str)
print(orgin_str)

#输出
abc
receive: abc
add after: abc add
abc

 通过输出可以看到传入的字符串在方法内添加了字符串,但是方法外的原来的字符串并没有被修改

3.2  为列表添加内容

orgin_list = ['abc','def']

def add_list(in_list):
    print(f"receive : {in_list}")
    in_list.append(' add')
    print(f"list add after : {in_list}")

print(orgin_list)
add_list(orgin_list)
print(orgin_list)

#输出
['abc', 'def']
receive : ['abc', 'def']
list add after : ['abc', 'def', ' add']
['abc', 'def', ' add']

通过输出可以看到,在方法内为列表添加的修改,原始变量也发生了变化。

3.3 解释

Python方法传参: 传递的是变量所指向的引用。函数内的变量和外部的变量指向同一个对象,对方法内部的变量进行修改时,是否影响外部变量,主要取决于指向的对象是否是可变对象。

可变对象:  修改该变量,因为指向同一个对象,所以函数外部的原始变量也会被修改,列表添加的列子。

不可变对象: 修改该变量,重新产生一个新的对象,并让内部的变量指向新的对象,原始变量指向原来的对象,所以修改对原来的对象没有产生影响。 字符串添加的例子

4、Python方法返回多个结果

python方法会返回多个值,这个其他语言就不一定支持,例如java,go等语言,方法只返回一个;

python方法没有明确指定返回值,返回多个结果的方法,就是把多个结果组装成一个元组返回;

def get_result():
    width = 100
    height = 200
    return width,height

print(type(get_result()))

# 输出
<class 'tuple'>

元组适合存放结构化的数据,可以存放一个对象的多个属性;

默认的元组只能通过索引获取值,不太方便,python提供一个: 有名字的元组,类似于key-value,可以通过名称访问成员

from collections import namedtuple
result = namedtuple('Result', 'width,height')
result_rsp = result(width=100, height=200)

print(result_rsp.width)
print(result_rsp.height)

5、字典中不存在的key

5.1 访问不存在的key

dict[key]  如果key不存在会抛出KeyError异常,有异常会导致方法执行结束,所以通过这种方式获取字典的值需要处理异常。

一般有三种方式:

1、提前判断key是否存在,再访问。 

person = {"name": "jerry", "age": 18, "address": "wuhan"}
# print(person['money'])
if 'money' in person:
    result = person['money']
    print(result)
else:
    result = 0
    print(result)

2 、try... except 处理这异常。这种方式优于第一种。 

person = {"name": "jerry", "age": 18, "address": "wuhan"}
try:
    result = person['money']
    print(result)
except KeyError:
    result = 0
    print(result)

3、如果只是为了获取值,如果key不存在返回默认值,这种方式更加简单dict.get(key,default)

person = {"name": "jerry", "age": 18, "address": "wuhan"}
# 如果不存在就,返回默认值0
person.get('money', 0)

5.2 修改不存在的key

1、如果key不存在,就会抛出异常,捕获异常处理

person = {"name": "jerry", "age": 18, "address": "wuhan"}

## 修改
try:
    person['money'].append('value')
except KeyError:
    person['money'] = ['value']

print(person)

2、dict.setdefault(key,default=None) 方式,可以省去异常捕获。

当key不存在时,就会把key放入该dict,并且设置值为默认值,并返回该值。

当key存在时,就会直接返回dict中key对应的值。 

person = {"name": "jerry", "age": 18, "address": "wuhan"}
person.setdefault('money', []).append('value')
print(person)
person.setdefault('money', []).append('hello')
print(person)
#输出
{'name': 'jerry', 'age': 18, 'address': 'wuhan', 'money': ['value']}
{'name': 'jerry', 'age': 18, 'address': 'wuhan', 'money': ['value', 'hello']}

5.3 删除不存在的key

删除dict中的key一般可以采用 del dict[key], 如果要删除的key不存在会抛出KeyError异常

person = {"name": "jerry", "age": 18, "address": "wuhan"}
try:
    del person['money']
except KeyError:
    # 忽略key不存在的
    pass

dict.pop(key,default) 删除字典给定键 key 所对应的值,返回值为被删除的值。 

  • 如果 key 存在 - 删除字典中对应的元素
  • 如果 key 不存在 - 返回设置指定的默认值 default
  • 如果 key 不存在且默认值 default 没有指定 - 触发 KeyError 异常
person = {"name": "jerry", "age": 18, "address": "wuhan"}
print(person.pop('name', None))
print(person.pop('money', None))
print(person)
#输出
jerry
None
{'age': 18, 'address': 'wuhan'}

6 字典推导式

对字典通过key进行过滤,并且对值进行处理,生成新的字典

person = {"name": "jerry", "age": 18, "address": "wuhan"}

person2 = {key: value + 10 for key, value in person.items() if key == 'age'}

print(person2)
#输出
{'age': 28}

7 字典的有序性

Python3.6 以前,开发者默认 : python的字典是无序的,无序是指按照顺序放进去,无法按照顺序取出来。但是python3.6 优化了底层实现,python3.7 已经默认 python字典是有序的,取出来的顺序和放进去的顺序是一致。

字典的底层key的存储是哈希表存储的,就是key必须是一个可以哈希的对象。

d = {}
for x in range(10):
    d[str(x)] = x

print(d)

for x in d:
    print(x)

#输出 python 2.7 .18
{'1': 1, '0': 0, '3': 3, '2': 2, '5': 5, '4': 4, '7': 7, '6': 6, '9': 9, '8': 8}
1
0
3
2
5
4
7
6
9
8
#输出 python3.9 多次执行结果都是顺序的
{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
0
1
2
3
4
5
6
7
8
9

8 集合set可以存放那些对象?

集合set中只能存放可哈希的对象,就是调用内置函数hash(obj),返回一个整型结果的对象,如果不能被哈希则抛出异常KeyError: unhashable ;

是否可哈希总结:

1、所有不可变的内置型,都是可以哈希的, str 、int、tuple(有条件)、frozenset 等

2、所有可变的内置类型,都是不可哈希的,list,dict,set 等

3、对于不可变的类型,tuple和frozenset ,  仅当所有成员都是不可变时,才是可以哈希的对象

4、用户自定义的class的实例对象都是可以哈希的。

set_test = set()
set_test.add('123')
set_test.add('name')
tuple_one = (1,2,3)
set_test.add(tuple_one)
print(set_test)
tuple_two = (1,2,['12','23'])
set_test.add(tuple_two)
#输出
{'name', (1, 2, 3), '123'}
TypeError: unhashable type: 'list'

tuple_one 可以添加成功,tuple_two 添加失败。

9 深拷贝与浅拷贝

python中对象拷贝,如果在操作一个可变对象时,不希望影响原始数据,先拷贝再修改,不拷贝原始对象就修改,可能会对原始数据产生影响。

浅拷贝

通过copy模块下的copy方法实现浅拷贝

import copy
nums = [1,2,3,4]
nums_copy = copy.copy(nums)
nums[2] = 20
nums_copy[1] = 10

print(nums)
print(nums_copy)
# 输出
[1, 2, 20, 4]
[1, 10, 3, 4]

浅拷贝的其他几种实现

1、通过list和dict 这种构造函数,能够实现浅拷贝

2、通过切片实现浅拷贝。

3、list和dict自带的copy方法

nums = [1,2,3,4]
nums_list_copy = list(nums)

d = {'name':'jerry', 'age':18}
dict_copy = dict(d.items())

nums_copy_2 = nums[:]


nums_copy_3 = nums.copy()
d_copy = d.copy()

浅拷贝的问题:有嵌套层级的时候

import copy

nums = [1, 2, 3, ["name", "age"]]
nums_copy = copy.copy(nums)
nums_list_copy = list(nums)
nums_copy_2 = nums[:]
nums_copy_3 = nums.copy()

nums[3].append("address")

print(nums)
print(nums_copy)
print(nums_list_copy)
print(nums_copy_2)
print(nums_copy_3)
#输出
[1, 2, 3, ['name', 'age', 'address']]
[1, 2, 3, ['name', 'age', 'address']]
[1, 2, 3, ['name', 'age', 'address']]
[1, 2, 3, ['name', 'age', 'address']]
[1, 2, 3, ['name', 'age', 'address']]

通过输出可以看到,修改原始数据,copy的新数据也发生了改变, 本质是copy的list中嵌套的list只是copy了地址,两个对象中嵌套的list指向同一个list,修改会彼此影响。

print(id(nums),id(nums_copy))
print(id(nums[3]), id(nums_copy[3]))
# 输出
4552674880 4554515648
4554395136 4554395136

深拷贝

深拷贝就是为了解决上面的嵌套问题,彻底copy对象,新旧对象修改不被互相影响。

使用copy.deepcopy()函数实现:

import copy

nums = [1, 2, 3, ["name", "age"]]
nums_copy = copy.deepcopy(nums)

nums[3].append("address")

print(nums)
print(nums_copy)

print(id(nums),id(nums_copy))
print(id(nums[3]), id(nums_copy[3]))
# 输出
[1, 2, 3, ['name', 'age', 'address']]
[1, 2, 3, ['name', 'age']]
4470107712 4471952704
4471832128 4471955200

10 生成器generator

生成器(generator)是python里特殊的数据类型,可以不断返回给调用方的生成内容的类型。

按需生成,类似其他语言的懒加载,先返回结果生成器,再调用next() 时候才会再去生成结果并返回。这是python的一种编程思想-按需返回,而不是一次返回所有列表。

print(type(range(10)))
#输出
<class 'range'>

range(num) 返回的数列就是一个生成器,并不是返回了一个列表,只是在迭代的时候才会不断生成新的数字;

定义生成器: 

def generator_num(max_num):
    """返回0-max之间的偶数"""
    for x in range(max_num):
        print(f"被调用了一次-{x}")
        if x % 2 == 0:
            yield x

print(type(generator_num(10)))
for i in generator_num(10):
    print(i)
#输出
<class 'generator'>
被调用了一次-0
0
被调用了一次-1
被调用了一次-2
2
被调用了一次-3
被调用了一次-4
4
被调用了一次-5
被调用了一次-6
6
被调用了一次-7
被调用了一次-8
8
被调用了一次-9

通过循环迭代生成器,可以看到,只有在被迭代的时候,生成器内部才开始调用。

next(generator) 可以获得迭代器里面的内容。

list(generator) 可以直接将生成器的结果转化为list对象。

用生成器替代列表

如果函数的处理是:初始化容器-->循环处理元素-->将结果存入新的容器---> 返回容器

一般这种处理过程会这样写:

def process_items(items):
    result = []
    for item in items:
        # do something 可能处理时间比较长,可能这个items量非常的大
        result_item = 'xxx'
        result.append(result_item)
    return result

1、问题1 : 可能这个items量非常的大,可能 单个元素处理时间比较长,返回的result比较大,也会比较占用内存。

2、问题2: 返回的 result_item 满足特定条件中断执行。目前函数里面也是无法做到。

解决这两个问题,就是需要改写为生成器

def process_items(items):
    for item in items:
        # do something 可能处理时间比较长,可能这个items量非常的大
        result_item = 'xxx'
        yield result_item

# 调用 
list = list(range(10))
for result_item in process_items(items=list):
    # 如果满足条件,就会终止执行,也会结束生成器的执行
    if result_item.has_expired():
        break
    # todo something

11 容器的底层实现

list的两种插入数据比较:

def list_append():
    l = []
    for x in range(5000):
        l.append(x)


def list_insert():
    l = []
    for x in range(5000):
        l.insert(0,x)


append_time = timeit.timeit(setup='from __main__ import list_append', stmt='list_append()', number=10000)
print("append_time :", append_time)

insert_time = timeit.timeit(setup='from __main__ import list_insert', stmt='list_insert()', number=10000)
print("insert_time :", insert_time)

# 输出
append_time : 2.770407401
insert_time : 67.36323991100001

两种添加列表的方式不同,生成一个长度为5000的列表,耗时相差30倍。这种原因是list的底层实现时数组,数组追加操作的平均时间复杂度是O(1), 如果数组从头部插入成员,其他成员都要移动位置, 所以平均时间复杂度是O(n);

python有没有数组类型? 其实python没有数组类型,其他语言基本都有数组这个类型。python提供的list比数组的功能要更加强大,一般语言的数组是存放多个同类对象数据,python的list可以存放多种不同功类型的对象数据;

如果需要经常在列表头部插入数据,可以采用collections 提供的 deque ,底层实现了双端队列,头部和尾部添加成员复杂度都是O(1)。

from collections import deque

def deque_append():
    l = deque()
    for x in range(5000):
        l.append(x)

def deque_appendleft():
    l = deque()
    for x in range(5000):
        l.appendleft(x)

append_time = timeit.timeit(setup='from __main__ import deque_append', stmt='deque_append()', number=10000)
print("append_time :", append_time)

insert_time = timeit.timeit(setup='from __main__ import deque_appendleft', stmt='deque_appendleft()', number=10000)
print("insert_time :", insert_time)
# 输出
append_time : 2.772019173
insert_time : 2.7395239540000005

列表的查找问题:如果列表特别大,查找某个成员是否存在,需要从前往后逐个对比,如果是最后一个,平均时间复杂度就是O(n) 。 如果判断成员是否存在,有些地方会你可能会看到,可以将列表转换为集合,再通过集合查找可以提高效率。集合是哈希表数据结构,查找快,好像没有什么问题,但是实际测试, 把一个大的列表转换为集合,存储也是需要一定时间的。这么做实际上会降低效率,不信自己测试去看看吧。 

import time

l = []
for x in range(50000001):
    l.append(x)

start = time.time()
print(50000000 in l, time.time() -start)

start = time.time()
s = set(l)
print(time.time() - start)
start = time.time()
print(50000000 in s,time.time() - start )
# 输出
True 0.581557035446167
4.345677137374878
True 2.1457672119140625e-06

12 两个字典的合并

两个字典的合并

1、 d1.update(d2) , 这种方式合并字典d1会被修改,有副作用的合并。

d_1 = {'name': 'jerry', 'age': 18}
d_2 = {'name': 'tom', 'adress': 'wuhan'}

d_1.update(d_2)
print(d_1)

2、利用动态解包的特点 **dict 解包合并,可以生成新的字典,对原理的数据无副作用,注意解包:默认进行了浅拷贝。

d_1 = {'name': 'jerry', 'age': 18}
d_2 = {'name': 'tom', 'adress': 'wuhan'}

d_new = {**d_1, **d_2}
print(d_new)
print(d_1)
# 输出
{'name': 'tom', 'age': 18, 'adress': 'wuhan'}
{'name': 'jerry', 'age': 18}

3、python 3.9 的 合并运算

注意;运算顺序不同结果会有差异,同样的key,右边的会把左边的修改

d_1 = {'name': 'jerry', 'age': 18}
d_2 = {'name': 'tom', 'adress': 'wuhan'}

print(d_1 | d_2)
print(d_2 | d_1)
# 输出
{'name': 'tom', 'age': 18, 'adress': 'wuhan'}
{'name': 'jerry', 'adress': 'wuhan', 'age': 18}

使用*obj可以解包任何可迭代对象, 使用**dict解开dict包,这两种方式在python传入参数的时候很常见。

13  列表去重复且保持原有顺序

一般的set可以去重但是无法保持原来顺序,如果要保持原来的顺序需要使用OrderDict来完成这件事。

from collections import OrderedDict

num = [2, 3, 10, 20,'123', 5, 2, 30, 3, ]
print(num)
# 虽然去重了,但是原来的顺序乱了,如果是数字的话,好像还默认给排序了。
s = list(set(num))
print(s)

# 保持原有顺序,且去重
num_new = list(OrderedDict.fromkeys(num).keys())
print(num_new)

## 输出
[2, 3, 10, 20, '123', 5, 2, 30, 3]
[2, 3, 5, 10, '123', 20, 30]
[2, 3, 10, 20, '123', 5, 30]

14 代码优化

需求:处理http的请求日志,分析不同url的性能占比,  要求如下:

原始数据:
/v1/login/ 200
/v2/admin/ 260
/v1/queryData/ 400
...

输出结果:
Path: /v1/login/
Total request: 800
Performance: 
   - Less than 100ms : 100
   - Between 100 and 300ms : 200 
   - Between 300 and 1s :  200 
   - More than 1s : 300
Path: ...

测试数据:

/v1/login/ 200
/v2/admin/ 300
/v1/queryData/ 400
/v1/login/ 100
/v2/admin/ 89
/v1/queryData/ 400
/v1/login/ 98
/v2/admin/ 80
/v1/queryData/ 400
/v1/login/ 200
/v2/admin/ 260
/v1/queryData/ 400
/v1/login/ 1000
/v2/admin/ 800
/v1/queryData/ 1080
/v1/login/ 200
/v2/admin/ 260
/v1/queryData/ 400
/v1/login/ 200
/v2/admin/ 1050
/v1/queryData/ 400
/v1/login/ 2000
/v2/admin/ 260
/v1/queryData/ 250
/v1/login/ 400
/v2/admin/ 800
/v1/queryData/ 900

 第一个版本代码

def analyze_log():
    path_dict = {}
    with open("log.txt", "r") as file:
        for line in file:
            path, time_cost = line.strip().split()
            rsp_time = int(time_cost)

            if rsp_time < 100:
                level = 'Less than 100ms'
            elif rsp_time < 300:
                level = 'Between 100 and 300ms'
            elif rsp_time < 1000:
                level = 'Between 300 and 1s'
            else:
                level = 'More than 1s'

            # 不存在加入空
            if path not in path_dict:
                path_dict[path] = {}

            # 计数
            try:
                path_dict[path][level] += 1
            except KeyError:
                path_dict[path][level] = 1

    for path, result in path_dict.items():
        print(f'===Path:  {path}')
        total = sum(result.values())
        print(f'Total request: {total}')
        print(f'Performance:')
        for level_name, count in result.items():
            print(f'    - {level_name} : {count}')

if __name__ == '__main__':
    analyze_log()

第一个版本代码可以基本满足需求:

#结果如下
===Path:  /v1/login/
Total request: 9
Performance:
    - Between 100 and 300ms : 5
    - Less than 100ms : 1
    - More than 1s : 2
    - Between 300 and 1s : 1
===Path:  /v2/admin/
Total request: 9
Performance:
    - Between 300 and 1s : 3
    - Less than 100ms : 2
    - Between 100 and 300ms : 3
    - More than 1s : 1
===Path:  /v1/queryData/
Total request: 9
Performance:
    - Between 300 and 1s : 7
    - More than 1s : 1
    - Between 100 and 300ms : 1

但是存在以下问题

1、级别level  这种类型的数据,最好用枚举替代,定义比较清楚,后续修改级别也只需修改一处。

2、所有功能都融合在一个方法里面,读取文件,处理逻辑和输出,这个最好分开去处理。

3、if path not in path_dict 和 try... expect的写法可以使用get() 和setdefault() 来优化。

4、 返回的统计结果没有按照顺序优化,这个可以通过枚举的定义的level来排序优化。

第二个优化版本:

from enum import Enum

class PerfLevel(str, Enum):
    Level_100 = 'Less than 100ms'
    Level_300 = 'Between 100 and 300ms'
    Level_1000 = 'Between 300 and 1s'
    Level_M_1000 = 'More than 1s'

def analyze_log():
    path_dict = {}
    with open("log.txt", "r") as file:
        for line in file:
            path, time_cost = line.strip().split()
            rsp_time = int(time_cost)

            if rsp_time < 100:
                level = PerfLevel.Level_100
            elif rsp_time < 300:
                level = PerfLevel.Level_300
            elif rsp_time < 1000:
                level = PerfLevel.Level_1000
            else:
                level = PerfLevel.Level_M_1000

            path_dict.setdefault(path, {})

            num = path_dict[path].get(level, 0)
            path_dict[path][level] = num + 1

    for path, result in path_dict.items():
        print(f'===Path:  {path}')
        total = sum(result.values())
        print(f'Total request: {total}')
        print(f'Performance:')
        sorted_result = sorted(result.items(), key=lambda p: list(PerfLevel).index(p[0]))
        for level_name, count in sorted_result:
            print(f'    - {level_name} : {count}')


if __name__ == '__main__':
    analyze_log()

进一步优化代码:

1、通过 defaultdict(default_factory,...)  类型优化字典的的操作,defaultdict是一种特殊类型的字典,接受一个default_factory 函数作为参数,如果d[key]访问,key不存在,就是调用default_factory生成结果作为value,将key-value 存入字典。

from collections import defaultdict

d = defaultdict(int)
d['name'] += 1
print(d)
print(dict(d))

def get_default_value():
    return 100

d_2 = defaultdict(get_default_value)
# key不存在就会调用默认值,而且存储到了dict中,并且返回了值
d_2['money'] += 1
d_2['name'] = 'jerry'
print(dict(d_2))
# 输出 
defaultdict(<class 'int'>, {'name': 1})
{'name': 1}
{'money': 101, 'name': 'jerry'}

2、使用MultableMapping创建自定义的字典类型。继承MultableMapping的抽象类来实现。

from enum import Enum
from collections.abc import MutableMapping
from collections import defaultdict


class PerfLevel(str, Enum):
    Level_100 = 'Less than 100ms'
    Level_300 = 'Between 100 and 300ms'
    Level_1000 = 'Between 300 and 1s'
    Level_M_1000 = 'More than 1s'


class PerfLevelDict(MutableMapping):

    def __init__(self):
        self.data = defaultdict(int)

    def __setitem__(self, key, value) -> None:
        self.data[self.compute_level(key)] = value

    def __delitem__(self, key) -> None:
        del self.data[key]

    def __getitem__(self, key):
        return self.data[self.compute_level(key)]

    def __len__(self):
        return len(self.data)

    def __iter__(self):
        return iter(self.data)

    @staticmethod
    def compute_level(time_str):
        if time_str in list(PerfLevel):
            return time_str

        rsp_time = int(time_str)
        if rsp_time < 100:
            return PerfLevel.Level_100
        elif rsp_time < 300:
            return PerfLevel.Level_300
        elif rsp_time < 1000:
            return PerfLevel.Level_1000
        return PerfLevel.Level_M_1000


def analyze_log():
    path_dict = defaultdict(PerfLevelDict)
    with open("log.txt", "r") as file:
        for line in file:
            path, time_cost = line.strip().split()
            path_dict[path][time_cost] +=1

    for path, result in path_dict.items():
        print(f'===Path:  {path}')
        total = sum(result.values())
        print(f'Total request: {total}')
        print(f'Performance:')
        sorted_result = sorted(result.items(), key=lambda p: list(PerfLevel).index(p[0]))
        for level_name, count in sorted_result:
            print(f'    - {level_name} : {count}')


if __name__ == '__main__':
    analyze_log()

代码优化是更加结构化了,逻辑被封装进去自定义的字典里面了,但是代码的可读性和理解性下降了,装逼是可以的,实际好像很少这么玩的。 

15 排序问题

列表有一个内置的list.sort()方法可以排序,会直接修改列表。还有一个 sorted() 内置函数,可以排序,它会从一个可迭代对象构建一个新的排序列表,不会修改原数据。

sort()方法和sorted()函数增加了key参数来指定一个函数,此函数将在每个元素比较前被调用。

key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。

一种常见的模式是使用对象的一些索引作为键对复杂对象进行排序。

student_tuples = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'D', 10), ('jerry', 'C', 5)]

sorted_student = sorted(student_tuples, key=lambda x: x[1])
print(sorted_student)

sorted_student_2 = sorted(student_tuples, key=lambda x: x[2])
print(sorted_student_2)
# 输出
[('john', 'A', 15), ('jane', 'B', 12), ('jerry', 'C', 5), ('dave', 'D', 10)]
[('jerry', 'C', 5), ('dave', 'D', 10), ('jane', 'B', 12), ('john', 'A', 15)]

字典通过key排序或者通过value排序。

# 对键排序
dict1={'a':2,'e':3,'f':8,'d':4}
list1= sorted(dict1.items(),key=lambda x:x[0])
print(list1)

# 对值排序
dict1={'a':2,'e':3,'f':8,'d':4}
list1= sorted(dict1.items(),key=lambda x:x[1])
print(list1)

字典组成的列表排序:

dic = [{"goods_id":3,"user_id":11, "score":0.8}, 
       {"goods_id":1,"user_id":22, "score":0.1},
       {"goods_id":2,"user_id":33, "score":0.5}]
sorted(dic, key=lambda x:x['score'], reverse=True)

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值