35个高级Python知识点总结(转)

时间:2019-06-14
本文章向大家介绍35个高级Python知识点总结(转),主要包括35个高级Python知识点总结(转)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

No.1 一切皆对象

众所周知,Java中强调“一切皆对象”,但是Python中的面向对象比Java更加彻底,因为Python中的类(class)也是对象,函数(function)也是对象,而且Python的代码和模块也都是对象。

  • Python中函数和类可以赋值给一个变量
  • Python中函数和类可以存放到集合对象中
  • Python中函数和类可以作为一个函数的参数传递给函数
  • Python中函数和类可以作为返回值

Step.1

# 首先创建一个函数和一个Python3.x的新式类
class Demo(object):
    def __init__(self):
        print("Demo Class")
# 定义一个函数
def function():
    print("function")
# 在Python无论是函数,还是类,都是对象,他们可以赋值给一个变量
class_value = Demo
func_value = function
# 并且可以通过变量调用
class_value()   # Demo Class
func_value()    # function

Step.2

# 将函数和类添加到集合中
obj_list = []
obj_list.append(Demo)
obj_list.append(function)
# 遍历列表
for i in obj_list:
    print(i)
    # <class '__main__.Demo'>
    # <function function at 0x0000020D681B3E18>

Step.3

# 定义一个具体函数
def test_func(class_name, func_name):
    class_name()
    func_name()
# 将类名和函数名传入形参列表
test_func(Demo, function)
# Demo Class
# function

Step.4

# 定义函数实现返回类和函数
def test_func2():
    return Demo

def test_func3():
    return function
# 执行函数
test_func2()() # Demo Class
test_func3()() # function

No.2 关键字type、object、class之间的关系

在Python中,object的实例是typeobject是顶层类,没有基类;type的实例是typetype的基类是object。Python中的内置类型的基类是object,但是他们都是由type实例化而来,具体的值由内置类型实例化而来。在Python2.x的语法中用户自定义的类没有明确指定基类就默认是没有基类,在Python3.x的语法中,指定基类为object

# object是谁实例化的?
print(type(object))      # <class 'type'>

# object继承自哪个类?
print(object.__bases__)  # ()

# type是谁实例化的?
print(type(type))        # <class 'type'>

# type继承自哪个类?
print(type.__bases__)    # (<class 'object'>,)

# 定义一个变量
value = 100

# 100由谁实例化?
print(type(value))       # <class 'int'>

# int由谁实例化?
print(type(int))         # <class 'type'>

# int继承自哪个类?
print(int.__bases__)     # (<class 'object'>,)
# Python 2.x的旧式类
class OldClass():
    pass

# Python 3.x的新式类
class NewClass(object):
    pass

No.3 Python的内置类型

在Python中,对象有3个特征属性:

  • 在内存中的地址,使用id()函数进行查看
  • 对象的类型
  • 对象的默认值

Step.1 None类型

在Python解释器启动时,会创建一个None类型的None对象,并且None对象全局只有一个。

Step.2 数值类型

  • ini类型
  • float类型
  • complex类型
  • bool类型

Step.3 迭代类型

在Python中,迭代类型可以使用循环来进行遍历。

Step.4 序列类型

  • list
  • tuple
  • str
  • array
  • range
  • bytes, bytearray, memoryvie(二进制序列)

Step.5 映射类型

  • dict

Step.6 集合类型

  • set
  • frozenset

Step.7 上下文管理类型

  • with语句

Step.8 其他类型

  • 模块
  • class
  • 实例
  • 函数
  • 方法
  • 代码
  • object对象
  • type对象
  • ellipsis(省略号)
  • notimplemented

NO.4 魔法函数

Python中的魔法函数使用双下划线开始,以双下划线结尾。关于详细介绍请看我的文章——《全面总结Python中的魔法函数》。

No.5 鸭子类型与白鹅类型

鸭子类型是程序设计中的推断风格,在鸭子类型中关注对象如何使用而不是类型本身。鸭子类型像多态一样工作但是没有继承。鸭子类型的概念来自于:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

# 定义狗类
class Dog(object):
    def eat(self):
        print("dog is eatting...")

# 定义猫类
class Cat(object):
    def eat(self):
        print("cat is eatting...")

# 定义鸭子类
class Duck(object):
    def eat(self):
        print("duck is eatting...")

# 以上Python中多态的体现

# 定义动物列表
an_li = []
# 将动物添加到列表
an_li.append(Dog)
an_li.append(Cat)
an_li.append(Duck)

# 依次调用每个动物的eat()方法
for i in an_li:
    i().eat()

# dog is eatting...
# cat is eatting...
# duck is eatting...

白鹅类型是指只要 cls 是抽象基类,即 cls 的元类是 abc.ABCMeta ,就可以使用 isinstance(obj, cls) 。

No.6 协议、 抽象基类、abc模块和序列之间的继承关系

  • 协议:Python中的非正式接口,是允许Python实现多态的方式,协议是非正式的,不具备强制性,由约定和文档定义。
  • 接口:泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被内部修改而不影响外界其他实体与其交互的方式。

我们可以使用猴子补丁来实现协议,那么什么是猴子补丁呢?

猴子补丁就是在运行时修改模块或类,不去修改源代码,从而实现目标协议接口操作,这就是所谓的打猴子补丁。

Tips:猴子补丁的叫法起源于Zope框架,开发人员在修改Zope的Bug时,经常在程序后面追加更新的部分,这些杂牌军补丁的英文名字叫做guerilla patch,后来写成gorllia,接着就变成了monkey

猴子补丁的主要作用是:

  • 在运行时替换方法、属性
  • 在不修改源代码的情况下对程序本身添加之前没有的功能
  • 在运行时对象中添加补丁,而不是在磁盘中的源代码上

应用案例:假设写了一个很大的项目,处处使用了json模块来解析json文件,但是后来发现ujson比json性能更高,修改源代码是要修改很多处的,所以只需要在程序入口加入:

import json
# pip install ujson
import ujson  

def monkey_patch_json():  
    json.__name__ = 'ujson'  
    json.dumps = ujson.dumps  
    json.loads = ujson.loads  

monkey_patch_json()

Python 的抽象基类有一个重要实用优势:可以使用 register 类方法在终端用户的代码中把某个类 “声明” 为一个抽象基类的 “虚拟” 子 类(为此,被注册的类必腨满足抽象其类对方法名称和签名的要求,最重要的是要满足底 层语义契约;但是,开发那个类时不用了解抽象基类,更不用继承抽象基类 。有时,为了让抽象类识别子类,甚至不用注册。要抑制住创建抽象基类的冲动。滥用抽象基类会造成灾难性后果,表明语言太注重表面形式 。

  • 抽象基类不能被实例化(不能创建对象),通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。
  • 判定某个对象的类型
  • 强制子类必须实现某些方法

抽象基类的定义与使用

import abc

# 定义缓存类
class Cache(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def get(self, key):
        pass

    @abc.abstractmethod
    def set(self, key, value):
        pass

# 定义redis缓存类实现Cache类中的get()和set()方法
class RedisCache(Cache):

    def set(self, key):
        pass

    def get(self, key, value):
        pass

值得注意的是:Python 3.0-Python3.3之间,继承抽象基类的语法是class ClassName(metaclass=adc.ABCMeta),其他版本是:class ClassName(abc.ABC)

  • collections.abc模块中各个抽象基类的UML类图

No.7 isinstence和type的区别

class A(object):
    pass

class B(A):
    pass

b = B()

print(isinstance(b, B))
print(isinstance(b, A))
print(type(b) is B)
print(type(b) is A)

# True
# True
# True
# False

No.8 类变量和实例变量

  • 实例变量只能通过类的实例进行调用
  • 修改模板对象创建的对象的属性,模板对象的属性不会改变
  • 修改模板对象的属性,由模板对象创建的对象的属性会改变
# 此处的类也是模板对象,Python中一切皆对象
class A(object):

    #类变量
    number = 12

    def __init__(self):
        # 实例变量
        self.number_2 = 13

# 实例变量只能通过类的实例进行调用
print(A.number)      # 12
print(A().number)    # 12
print(A().number_2)  # 13

# 修改模板对象创建的对象的属性,模板对象的属性不会改变
a = A()
a.number = 18
print(a.number)      # 18
print(A().number)    # 12
print(A.number)      # 12

# 修改模板对象的属性,由模板对象创建的对象的属性会改变
A.number = 19
print(A.number)      # 19
print(A().number)    # 19

No.9 类和实例属性以及方法的查找顺序

  • 在Python 2.2之前只有经典类,到Python2.7还会兼容经典类,Python3.x以后只使用新式类,Python之前版本也会兼容新式类
  • Python 2.2 及其之前类没有基类,Python新式类需要显式继承自object,即使不显式继承也会默认继承自object
  • 经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的.而新式类是采用C3算法
  • 经典类没有MRO和instance.mro()调用的

假定存在以下继承关系:

class D(object):
    def say_hello(self):
        pass

class E(object):
    pass

class B(D):
    pass

class C(E):
    pass

class A(B, C):
    pass

采用DFS(深度优先搜索算法)当调用了A的say_hello()方法的时候,系统会去B中查找如果B中也没有找到,那么去D中查找,很显然D中存在这个方法,但是DFS对于以下继承关系就会有缺陷:

class D(object):
    pass

class B(D):
    pass

class C(D):
    def say_hello(self):
        pass

class A(B, C):
    pass

在A的实例对象中调用say_hello方法时,系统会先去B中查找,由于B类中没有该方法的定义,所以会去D中查找,D类中也没有,系统就会认为该方法没有定义,其实该方法在C中定义了。所以考虑使用BFS(广度优先搜索算法),那么问题回到第一个继承关系,假定C和D具备重名方法,在调用A的实例的方法时,应该先在B中查找,理应调用D中的方法,但是使用BFS的时候,C类中的方法会覆盖D类中的方法。在Python 2.3以后的版本中,使用C3算法:

# 获取解析顺序的方法
类名.mro()
类名.__mro__
inspect.getmro(类名)

使用C3算法后的第二种继承顺序:

class D(object):
    pass

class B(D):
    pass

class C(D):
    def say_hello(self):
        pass

class A(B, C):
    pass

print(A.mro()) # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]

使用C3算法后的第一种继承顺序:

class D(object):
    pass

class E(object):
    pass

class B(D):
    pass

class C(E):
    pass

class A(B, C):
    pass

print(A.mro()) 
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]

在这里仅介绍了算法的作用和演变历史,关于深入详细解析,请看我的其他文章——《从Python继承谈起,到C3算法落笔》。

No.10 类方法、实例方法和静态方法

class Demo(object):
    # 类方法
    @classmethod
    def class_method(cls, number):
        pass

    # 静态方法
    @staticmethod
    def static_method(number):
        pass

    # 对象方法/实例方法
    def object_method(self, number):
        pass

实例方法只能通过类的实例来调用;静态方法是一个独立的、无状态的函数,紧紧依托于所在类的命名空间上;类方法在为了获取类中维护的数据,比如:

class Home(object):

    # 房间中人数
    __number = 0

    @classmethod
    def add_person_number(cls):
        cls.__number += 1

    @classmethod
    def get_person_number(cls):
        return cls.__number

    def __new__(self):
        Home.add_person_number()
        # 重写__new__方法,调用object的__new__
        return super().__new__(self)

class Person(Home):

    def __init__(self):

        # 房间人员姓名
        self.name = 'name'

    # 创建人员对象时调用Home的__new__()方法

tom = Person()
print(type(tom))   # <class '__main__.Person'>
alice = Person()
bob = Person()
test = Person()

print(Home.get_person_number())

No.11 数据封装和私有属性

Python中使用双下划线+属性名称实现类似于静态语言中的private修饰来实现数据封装。

class User(object):

    def __init__(self, number):
        self.__number = number
        self.__number_2 = 0

    def set_number(self, number):
        self.__number = number

    def get_number(self):
        return self.__number

    def set_number_2(self, number2):
        self.__number_2 = number2
        # self.__number2 = number2

    def get_number_2(self):
        return self.__number_2
        # return self.__number2

u = User(25)
print(u.get_number())  # 25
# 真的类似于Java的反射机制吗?
print(u._User__number) # 25
# 下面又是啥情况。。。想不明白了T_T
u.set_number_2(18)
print(u.get_number_2()) # 18
print(u._User__number_2) 
# Anaconda 3.6.3    第一次是:u._User__number_2   第二次是:18
# Anaconda 3.6.5    结果都是 0 

# 代码我改成了正确答案,感谢我大哥给我指正错误,我保留了错误痕迹
# 变量名称写错了,算是个写博客突发事故,这问题我找了一天,万分感谢我大哥,我太傻B了,犯了低级错误
# 留给和我一样的童鞋参考我的错我之处吧!

# 正确结果:
# 25  25  18  18

No.12 Python的自省机制

自省(introspection)是一种自我检查行为。在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。

  • dir([obj]):返回传递给它的任何对象的属性名称经过排序的列表(会有一些特殊的属性不包含在内)
  • getattr(obj, attr):返回任意对象的任何属性 ,调用这个方法将返回obj中名为attr值的属性的值
  • ... ...

No.13 super函数

Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(type[, object-or-type]).xxx 。

super()函数用来调用MRO(类方法解析顺序表)的下一个类的方法。

No.14 Mixin继承

在设计上将Mixin类作为功能混入继承自Mixin的类。使用Mixin类实现多重继承应该注意:

  • Mixin类必须表示某种功能
  • 职责单一,如果要有多个功能,就要设计多个Mixin类
  • 不依赖子类实现,Mixin类的存在仅仅是增加了子类的功能特性
  • 即使子类没有继承这个Mixin类也可以工作
class Cat(object):

    def eat(self):
        print("I can eat.")

    def drink(self):
        print("I can drink.")

class CatFlyMixin(object):

    def fly(self):
        print("I can fly.")

class CatJumpMixin(object):

    def jump(self):
        print("I can jump.")

class TomCat(Cat, CatFlyMixin):
    pass

class PersianCat(Cat, CatFlyMixin, CatJumpMixin):
    pass

if __name__ == '__main__':

    # 汤姆猫没有跳跃功能
    tom = TomCat()
    tom.fly()
    tom.eat()
    tom.drink()

    # 波斯猫混入了跳跃功能
    persian = PersianCat()
    persian.drink()
    persian.eat()
    persian.fly()
    persian.jump()

No.25 上下文管理器with语句与contextlib简化

普通的异常捕获机制:

try:
    pass
except Exception as err:
    pass
else:
    pass
finally:
    pass

with简化了异常捕获写法:

class Demo(object):

    def __enter__(self):
        print("enter...")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exit...")

    def echo_hello(self):
        print("Hello, Hello...")

with Demo() as d:
    d.echo_hello()

# enter...
# Hello, Hello...
# exit...
import contextlib

# 使用装饰器
@contextlib.contextmanager
def file_open(file_name):
    # 此处写__enter___函数中定义的代码
    print("enter function code...")
    yield {}
    # 此处写__exit__函数中定义的代码
    print("exit function code...")

with file_open("json.json") as f:
    pass

# enter function code...
# exit function code...

No.26 序列类型的分类

  • 容器序列:list tuple deque
  • 扁平序列:str bytes bytearray array.array
  • 可变序列:list deque bytearray array
  • 不可变序列:str tuple bytes

No.27 +、+=、extend()之间的区别于应用场景

首先看测试用例:

# 创建一个序列类型的对象
my_list = [1, 2, 3]
# 将现有的序列合并到my_list
extend_my_list = my_list + [4, 5]

print(extend_my_list)  # [1, 2, 3, 4, 5]
# 将一个元组合并到这个序列
extend_my_list = my_list + (6, 7)
# 抛出异常 TypeError: can only concatenate list (not "tuple") to list
print(extend_my_list)

# 使用另一种方式合并
extend_my_list += (6, 7)
print(extend_my_list)  # [1, 2, 3, 4, 5, 6, 7]

# 使用extend()函数进行合并

extend_my_list.extend((7, 8))
print(extend_my_list)  # [1, 2, 3, 4, 5, 6, 7, 7, 8]

由源代码片段可知:

class MutableSequence(Sequence):

    __slots__ = ()

    """All the operations on a read-write sequence.

    Concrete subclasses must provide __new__ or __init__,
    __getitem__, __setitem__, __delitem__, __len__, and insert().

    """
    # extend()方法内部使用for循环来append()元素,它接收一个可迭代序列
    def extend(self, values):
        'S.extend(iterable) -- extend sequence by appending elements from the iterable'
        for v in values:
            self.append(v)
    # 调用 += 运算的时候就是调用该函数,这个函数内部调用extend()方法
    def __iadd__(self, values):
        self.extend(values)
        return self

No.28 使用bisect维护一个已排序的序列

import bisect

my_list = []
bisect.insort(my_list, 2)
bisect.insort(my_list, 9)
bisect.insort(my_list, 5)
bisect.insort(my_list, 5)
bisect.insort(my_list, 1)
# insort()函数返回接收的元素应该插入到指定序列的索引位置
print(my_list)  # [1, 2, 5, 5, 9]

No.29 deque类详解

deque是Python中一个双端队列,能在队列两端以$O(1)$的效率插入数据,位于collections模块中。

from collections import deque
# 定义一个双端队列,长度为3
d = deque(maxlen=3)

deque类的源码:

class deque(object):
    """
    deque([iterable[, maxlen]]) --> deque object
    一个类似列表的序列,用于对其端点附近的数据访问进行优化。
    """
    def append(self, *args, **kwargs):
        """ 在队列右端添加数据 """
        pass

    def appendleft(self, *args, **kwargs): 
        """ 在队列左端添加数据 """
        pass

    def clear(self, *args, **kwargs):
        """ 清空所有元素 """
        pass

    def copy(self, *args, **kwargs):
        """ 浅拷贝一个双端队列 """
        pass

    def count(self, value):
        """ 统计指定value值的出现次数 """
        return 0

    def extend(self, *args, **kwargs):
        """ 使用迭代的方式扩展deque的右端 """
        pass

    def extendleft(self, *args, **kwargs):
        """ 使用迭代的方式扩展deque的左端 """
        pass

    def index(self, value, start=None, stop=None): __doc__
        """
        返回第一个符合条件的索引的值
        """
        return 0

    def insert(self, index, p_object):
        """ 在指定索引之前插入 """
        pass

    def pop(self, *args, **kwargs): # real signature unknown
        """  删除并返回右端的一个元素 """
        pass

    def popleft(self, *args, **kwargs): # real signature unknown
        """ 删除并返回左端的一个元素 """
        pass

    def remove(self, value): # real signature unknown; restored from __doc__
        """ 删除第一个与value相同的值 """
        pass

    def reverse(self): # real signature unknown; restored from __doc__
        """ 翻转队列 """
        pass

    def rotate(self, *args, **kwargs): # real signature unknown
        """ 向右旋转deque N步, 如果N是个负数,那么向左旋转N的绝对值步 """
        pass

    def __add__(self, *args, **kwargs): # real signature unknown
        """ Return self+value. """
        pass

    def __bool__(self, *args, **kwargs): # real signature unknown
        """ self != 0 """
        pass

    def __contains__(self, *args, **kwargs): # real signature unknown
        """ Return key in self. """
        pass

    def __copy__(self, *args, **kwargs): # real signature unknown
        """ Return a shallow copy of a deque. """
        pass

    def __delitem__(self, *args, **kwargs): # real signature unknown
        """ Delete self[key]. """
        pass

    def __eq__(self, *args, **kwargs): # real signature unknown
        """ Return self==value. """
        pass

    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __getitem__(self, *args, **kwargs): # real signature unknown
        """ Return self[key]. """
        pass

    def __ge__(self, *args, **kwargs): # real signature unknown
        """ Return self>=value. """
        pass

    def __gt__(self, *args, **kwargs): # real signature unknown
        """ Return self>value. """
        pass

    def __iadd__(self, *args, **kwargs): # real signature unknown
        """ Implement self+=value. """
        pass

    def __imul__(self, *args, **kwargs): # real signature unknown
        """ Implement self*=value. """
        pass

    def __init__(self, iterable=(), maxlen=None): # known case of _collections.deque.__init__
        """
        deque([iterable[, maxlen]]) --> deque object

        A list-like sequence optimized for data accesses near its endpoints.
        # (copied from class doc)
        """
        pass

    def __iter__(self, *args, **kwargs): # real signature unknown
        """ Implement iter(self). """
        pass

    def __len__(self, *args, **kwargs): # real signature unknown
        """ Return len(self). """
        pass

    def __le__(self, *args, **kwargs): # real signature unknown
        """ Return self<=value. """
        pass

    def __lt__(self, *args, **kwargs): # real signature unknown
        """ Return self<value. """
        pass

    def __mul__(self, *args, **kwargs): # real signature unknown
        """ Return self*value.n """
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __ne__(self, *args, **kwargs): # real signature unknown
        """ Return self!=value. """
        pass

    def __reduce__(self, *args, **kwargs): # real signature unknown
        """ Return state information for pickling. """
        pass

    def __repr__(self, *args, **kwargs): # real signature unknown
        """ Return repr(self). """
        pass

    def __reversed__(self): # real signature unknown; restored from __doc__
        """ D.__reversed__() -- return a reverse iterator over the deque """
        pass

    def __rmul__(self, *args, **kwargs): # real signature unknown
        """ Return self*value. """
        pass

    def __setitem__(self, *args, **kwargs): # real signature unknown
        """ Set self[key] to value. """
        pass

    def __sizeof__(self): # real signature unknown; restored from __doc__
        """ D.__sizeof__() -- size of D in memory, in bytes """
        pass

    maxlen = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """maximum size of a deque or None if unbounded"""

    __hash__ = None

No.30 列表推导式、生成器表达式、字典推导式

  • 列表推导式

列表生成式要比操作列表效率高很多,但是列表生成式的滥用会导致代码可读性降低,并且列表生成式可以替换map()reduce()函数。

# 构建列表
my_list = [x for x in range(9)]
print(my_list)   # [0, 1, 2, 3, 4, 5, 6, 7, 8]

# 构建0-8中为偶数的列表
my_list = [x for x in range(9) if(x%2==0)]
print(my_list)   # [0, 2, 4, 6, 8]

# 构建0-8为奇数的列表,并将每个数字做平方运算

def function(number):
    return number * number

my_list = [function(x) for x in range(9) if x%2!=0]
print(my_list)   # [1, 9, 25, 49]
  • 生成器表达式

生成器表达式就是把列表表达式的中括号变成小括号。

# 构造一个生成器
gen = (i for i in range(9))

# 生成器可以被遍历
for i in gen:
    print(i)

生成器可以使用list()函数转换为列表:

# 将生成器转换为列表
li = list(gen)
print(li)
  • 字典推导式
d = {
    'tom': 18,
    'alice': 16,
    'bob': 20,
}
dict = {key: value for key, value in d.items()}
print(dict)  # {'tom': 18, 'alice': 16, 'bob': 20}
  • Set集合推导式
my_set = {i for i in range(9)}
print(my_set)   # {0, 1, 2, 3, 4, 5, 6, 7, 8}

No.31 Set与Dict的实现原理

Set和Dict的背后实现都是Hash(哈希)表,有的书本上也较散列表。Hash表原理可以参考我的算法与数学博客栏目,下面给出几点总结:

  • Set和Dict的效率高于List。
  • Se和Dict的Key必须是可哈希的元素。
  • 在Python中,不可变对象都是可哈希的,比如:str、fronzenset、tuple,需要实现__hash__()函数。
  • Dict内存空间占用多,但是速度快,Python中自定义对象或Python内部对象都是Dict包装的。
  • Dict和Set的元素存储顺序和元素的添加顺序有关,但是添加元素时有可能改变已有的元素顺序。
  • List会随着元素数量的增加,查找元素的时间也会增大。
  • Dict和Set不会随着元素数量的增加而查找时间延长。

No.32 Python中的集合类模块collections

defaultdict

defaultdictdict的基础上添加了default_factroy方法,它的作用是当key不存在的时候自动生成相应类型的value,defalutdict参数可以指定成listsetint等各种类型。

应用场景:

from collections import defaultdict

my_list = [
    ("Tom", 18),
    ("Tom", 20),
    ("Alice", 15),
    ("Bob", 21),
]

def_dict = defaultdict(list)

for key, val in my_list:
    def_dict[key].append(val)

print(def_dict.items())
# dict_items([('Tom', [18, 20]), ('Alice', [15]), ('Bob', [21])])

# 如果不考虑重复元素可以使用如下方式
def_dict_2 = defaultdict(set)

for key, val in my_list:
    def_dict_2[key].add(val)

print(def_dict_2.items())
# dict_items([('Tom', {18, 20}), ('Alice', {15}), ('Bob', {21})])

源码:

class defaultdict(Dict[_KT, _VT], Generic[_KT, _VT]):
    default_factory = ...  # type: Callable[[], _VT]

    @overload
    def __init__(self, **kwargs: _VT) -> None: ...
    @overload
    def __init__(self, default_factory: Optional[Callable[[], _VT]]) -> None: ...
    @overload
    def __init__(self, default_factory: Optional[Callable[[], _VT]], **kwargs: _VT) -> None: ...

原文地址:https://www.cnblogs.com/sqtu/p/11022379.html