python深入

234 阅读4分钟

1. GIL(全局解释器锁)

  • GIL是CPython解释器中存在的,一般解释器都是CPython,同一时刻只有一个线程在运行,而且不能利用CPU多核的特性,所以无法实现并行。

    1. 设置GIL锁

    2. 切换到一个线程执行

    3. 执行以下指令:

      • 执行指定数量的代码

      • 遇到延时(time.sleep、io操作、socket的recv、accept、content等)操作,线程让出控制权

    4. 释放GIL锁

    5. 切换出线程

    6. 重复上述步骤 所以,多线程和多进程、协程的应用场景:

    • 计算(CPU)密集型:进程
    • IO密集型:线程、协程

2. 深拷贝与浅拷贝

2.1 浅拷贝

浅拷贝就是拷贝对象的引用地址,内存地址不变 一般常见的浅拷贝有:

  • 切片

  • list() 非数据类型转换

  • dict.copy() 字典拷贝

  • 导入模块copy

      import copy
      
      copy.copy()
    

浅拷贝不能拷贝不可变类型数据,不可变类型中存在可变数据也不进行拷贝

2.2 深拷贝

深拷贝就是拷贝对象的所有,拷贝引用地址,改变内存地址并且复制其中的数据

    import copy
    
    copy.deepcopy()

深拷贝不能拷贝不可变类型,但其中只要存在一个可变类型的数据,就可做深拷贝

3.私有化

  • _x:单前置下划线,表示私有属性或方法,from xxx import * 不可以导入此类属性或方法,但其类对象和子类可以访问
  • __xx:双前置下划线,私有化xx,一般避免与子类中的属性命名冲突,无法在外部直接访问
  • xx:双前后下划线,用户名、或系统魔法方法

4. Python mro

4.1 什么是mro

mro即method resolution order(方法解释顺序),解决Python多继承出现的二义性问题: 例:

class A():
    def f(self):
        pass
class B(A):
    def f(self):
        pass
class C(A, B):
    def f(self):
        pass
class D(B, C):
    def f(self):
        pass
class E(C, D):
    def f(self):
        pass

Python中会产生这样的问题,利用C3算法可以确定子类中继承方法的顺序,该序列保存在子类对象__mro__中

4.2 快速确定mro顺序

  1. 确定继承关系
  2. 画出继承关系图
class D(object):
    pass
 
class E(object):
    pass
 
class F(object):
    pass
 
class C(D, F):
    pass
 
class B(E, D):
    pass
 
class A(B, C):
    pass
 
if __name__ == '__main__':
    print(A.__mro__)

  • 左边优先原则
  • 上下无法确定谁在左边,下级优先

5. *args,**kwargs

5.1 函数声明:

def func(*args, **kwargs)
  • *args可以接收不定长参数
  • **kwargs可以接受关键字参数

5.2 函数调用

def func(*args, **kwargs):
    pass

func(*args, **kwargs)

此时表示拆包

6. Python中类方法、实例方法、静态方法有何区别?

例:

class Test(object):
    def __init__(name,age):
        self.name = name
        self.age = age

    @classmethod
    def test1(cls,name): # cls,类对象
        obj = cls(name,18) # 类对象可以创建实例对象

    @staticmethod
    def test2():
        return age<18 and len(name)>6

    def test3(self): # self,实例对象
        pass

test = Test("sss",19)
  • 类方法:是类对象的方法,在定义时需要在上方使用"@classsmethod"进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用; 可以利用实例方法中cls即类对象创建一份实例对象,扩充的初始化__init__方法的参数限制
  • 实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;
  • 静态方法:是一个任意函数,在其上方使用@staticmethod进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系,一般作为类提供的工具方法存在

7. property属性

通过property将类中的方法提升为一个属性,隐藏具体逻辑,对外只需像属性一样访问即可调用方法并获得返回值,简化调用者获取数据的流程

  1. 装饰器的方式创建
class Date(objecct):
    def __init__(self):
        self.__name = "sss"
        
    @property
    def name(self):
        return self.__name
        
    @name.setter
    def name(self, value):
        self.__name = value
  1. 类属性来创建
class Foo(object):
    def get_bar(self):
        print("getter...")
        return "www"
        
    def set_bar(self, value):
        """必须两个参数"""
        print("setter...")
        return "set value" + value
        
    def del_bar(self):
        print("deleter...")
        return "www"

如果代码考虑Python版本的兼容性,用类属性的方式创建,否则优先考虑装饰器的方式

8. 上下文管理器、with

系统资源如文件、数据库连接、socket而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。为了避免每次都手动去关闭这些资源,可以使用with关键字,比如:

with open("output.txt", "r") as f:
    f.write("python")

with后面紧挨的语句返回的对象必须是一个上下文管理器,任何实现了__enter__()和__exit__()方法的对象都可称为上下文管理器。 例:

class SocketManager():
    def __init__(self, ip, port):
        self.addr = (ip, port)

    def __enter__(self):
        self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_socket.connect(self.addr)
        return self.tcp_socket

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.tcp_socket.close()


with SocketManager("127.0.0.1", 7890) as s:
    s.recv(1024)
    s.send(b"hello")

如果中间遇到异常close方法也会被调用

  1. with会判断后面的语句返回值是不是一个上下文管理器
  2. 如果该对象是上下文管理器,调用该对象的__enter__()方法,并交给as后面的变量
  3. 使用该变量进行业务逻辑操作,完事后,会自动调用该对象的__exit__()方法去释放资源