itemgetter是Python内置的operator模块中的函数之一,用于获取可迭代对象中的某个元素(或多个元素)或者对象的属性值。itemgetter函数可以接受一个或多个参数,每个参数可以是一个整数、一个字符串或一个可以调用的对象。
itemgetter函数是通过实现一个类,并在类中定义一个 __getitem__() 方法来实现的。
在类的实例化过程中,可以将要获取的元素的索引或属性名作为参数传递给类的构造方法,该参数会被保存在类的属性中。
当调用类的实例时,实际上是调用了 __getitem__() 方法,并将可迭代对象作为参数传递给该方法。
__getitem__() 方法会根据保存的参数,获取可迭代对象中指定元素的值或对象的指定属性值,并返回这个值。
# itemgetter函数的底层实现可以看做是以下代码:
class ItemGetter:
def __init__(self, *items):
self.items = items
def __getitem__(self, index):
if isinstance(index, int):
return lambda x: x[index]
elif isinstance(index, str):
return lambda x: getattr(x, index)
elif callable(index):
return lambda x: index(x)
else:
raise TypeError('Invalid argument type')
def itemgetter(*items):
return ItemGetter(*items)
# ItemGetter 类定义了一个构造方法 __init__(),该方法接受一个或多个参数,
# 这些参数表示要获取的元素的索引或属性名,并将它们保存在类的 items 属性中。
# 同时,ItemGetter 类还实现了一个特殊方法 __getitem__(),该方法接受一个可迭代对象作为参数,
# 并根据保存的 items 属性,获取可迭代对象中指定元素的值或对象的指定属性值。
#
# itemgetter() 函数实际上是对 ItemGetter 类的实例化,返回一个 ItemGetter 类的对象。
# 这个对象可以作为一个可调用的函数使用,并接受一个可迭代对象作为参数,
# 返回可迭代对象中指定元素的值或对象的指定属性值。
from operator import itemgetter
lst = ['a', 'b', 'c', 'd', 'e']
getter = itemgetter(2)
print(getter(lst)) # 'c'
lst = ['a', 'b', 'c', 'd', 'e']
getter = itemgetter(2, 4)
print(getter(lst)) # ('c', 'e')
dct = {'a': {'name': 'Alice', 'age': 23},
'b': {'name': 'Bob', 'age': 25},
'c': {'name': 'Charlie', 'age': 20}}
getter = itemgetter('name')
print(list(map(getter, dct.values()))) # ['Alice', 'Bob', 'Charlie']
from operator import itemgetter
from pprint import pprint
data_list = [
{"name": "java", "num_1": 10, "num_2": 1},
{"name": "c", "num_1": 8, "num_2": 96},
{"name": "go", "num_1": 160, "num_2": 0},
{"name": "html", "num_1": 20, "num_2": 1},
{"name": "vue", "num_1": 1, "num_2": 1},
]
# sorted() 函数默认升序
by_name = sorted(data_list, key=itemgetter('name'))
by_num_1 = sorted(data_list, key=itemgetter('num_1'))
pprint(by_name)
pprint(by_num_1)
# [{'name': 'c', 'num_1': 8, 'num_2': 96},
# {'name': 'go', 'num_1': 160, 'num_2': 0},
# {'name': 'html', 'num_1': 20, 'num_2': 1},
# {'name': 'java', 'num_1': 10, 'num_2': 1},
# {'name': 'vue', 'num_1': 1, 'num_2': 12}]
# [{'name': 'vue', 'num_1': 1, 'num_2': 12},
# {'name': 'c', 'num_1': 8, 'num_2': 96},
# {'name': 'java', 'num_1': 10, 'num_2': 1},
# {'name': 'html', 'num_1': 20, 'num_2': 1},
# {'name': 'go', 'num_1': 160, 'num_2': 0}]
# 先对num_2进行排序,如果有相同的,再按照num_1再次排序
by_num_1_num_2 = sorted(data_list, key=itemgetter('num_2', 'num_1'))
pprint(by_num_1_num_2)
# [{'name': 'go', 'num_1': 160, 'num_2': 0},
# {'name': 'vue', 'num_1': 1, 'num_2': 1},
# {'name': 'java', 'num_1': 10, 'num_2': 1},
# {'name': 'html', 'num_1': 20, 'num_2': 1},
# {'name': 'c', 'num_1': 8, 'num_2': 96}]
from operator import itemgetter
data_list = [
{"name": "java", "num_1": 10, "num_2": 1},
{"name": "c", "num_1": 8, "num_2": 96},
{"name": "go", "num_1": 160, "num_2": 0},
{"name": "html", "num_1": 20, "num_2": 1},
{"name": "vue", "num_1": 1, "num_2": 1},
]
min_data = min(data_list, key=itemgetter('num_1'))
print(min_data)
max_data = max(data_list, key=itemgetter('num_1'))
print(max_data)
# {'name': 'vue', 'num_1': 1, 'num_2': 1}
# {'name': 'go', 'num_1': 160, 'num_2': 0}
lst = [{'name': 'Alice', 'age': 23},
{'name': 'Bob', 'age': 25},
{'name': 'Charlie', 'age': 20}]
getter = itemgetter('age')
lst.sort(key=getter)
print(lst) # [{'name': 'Charlie', 'age': 20}, {'name': 'Alice', 'age': 23}, {'name': 'Bob', 'age': 25}]
lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
getter = itemgetter(1, 2)
print([getter(sublst) for sublst in lst]) # [(2, 3), (5, 6), (8, 9)]
operator模块中的attrgetter函数是一个用于获取对象属性的函数。其作用是传入一个属性名称,返回一个函数,这个函数可以获取对象中的该属性的值。
attrgetter函数的参数可以是字符串或者字符串组成的列表,用于指定要获取的属性。
如果属性不存在,会引发AttributeError异常。
attrgetter函数的用法非常灵活,它可以用于排序、过滤、分组等各种操作中,可以根据对象的某个属性进行排序或者分组。
此外,attrgetter函数还可以用于自定义对象的比较函数。
具体来说,attrgetter函数可以接受以下参数:
1.attrgetter(attr)
传入一个字符串表示要获取的属性名称。如果要获取的属性是嵌套的,可以用"."进行分隔,例如attrgetter("x.y.z")表示要获取的属性是x对象的y属性的z属性的值。
2.attrgetter(attr1, attr2, ...)
传入多个字符串表示要获取的多个属性名称。
3.attrgetter(*attrs)
传入一个由字符串组成的列表,表示要获取的多个属性名称。
attrgetter函数主要使用了Python的属性访问机制,即通过getattr函数动态获取对象的属性值。
其底层实现思路如下:
1、首先判断函数是否传入了参数,如果没有,则返回一个返回输入参数本身的函数,否则继续执行。
2、定义一个内部函数g,该函数接受一个对象作为参数,并返回一个元组。
3、在函数g中,使用循环遍历每个属性,并使用getattr函数获取该属性的值,将其存储在一个列表中。
4、最后将该列表转换为元组,并返回。
需要注意的是,attrgetter函数返回的是一个函数对象,而不是具体的属性值。
因为该函数可能会被多次调用,每次调用传入的对象可能不同,因此需要返回一个能够处理不同对象的函数。
可以简化代码,减少重复性的操作。
可以提高代码的可读性,易于理解和维护。
可以根据属性的值进行排序和比较,便于对对象进行操作。
在一些情况下,使用attrgetter函数可能会导致代码的执行速度慢,因为需要额外的函数调用和内存分配。
有时候使用attrgetter函数会使代码变得复杂,不容易理解。
对于一些特定的数据结构,如树和图等,使用attrgetter函数可能不太方便。
from operator import attrgetter
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'[{self.name}, {self.age}]'
people = [Person('Alice', 25), Person('Bob', 30), Person('Charlie', 20)]
sorted_people = sorted(people, key=attrgetter('age'))
print(sorted_people)
# [[Charlie, 20], [Alice, 25], [Bob, 30]]
from operator import attrgetter
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'{self.name}, {self.age}'
people = [Person('Alice', 25), Person('Bob', 30), Person('Charlie', 20)]
sorted_people = sorted(people, key=attrgetter('age'))
# sorted_people: [Charlie, 20, Alice, 25, Bob, 30]
from operator import attrgetter
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'{self.name}, {self.age}'
people = [Person('Alice', 25), Person('Bob', 30), Person('Charlie', 20)]
ages = list(map(attrgetter('age'), people))
# ages: [25, 30, 20]