python中的各项问题


Python内置类属性

  • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
  • __doc__ :类的文档字符串
  • __name__: 类名
  • __module__: 类定义所在的模块(类的全名是__main__.className,如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
  • __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

python 基础重载方法

序号 方法, 描述 & 简单的调用
1 __init__ ( self [,args…] ) 构造函数 简单的调用方法: obj = className(args)
2 __del__( self ) 析构方法, 删除一个对象 简单的调用方法 : del obj
3 __repr__( self ) 转化为供解释器读取的形式 简单的调用方法 : repr(obj)
4 __str__( self ) 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj)
5 __cmp__ ( self, x ) 对象比较 简单的调用方法 : cmp(obj, x)

python 正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。

待添加

python中的拷贝

Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。本模块提供了通用的浅层复制和深层复制操作,(如下所述)。

接口摘要:

  • copy.copy(x)

    返回 x 的浅层复制。

  • copy.deepcopy(x[, memo])

    返回 x 的深层复制。

浅层与深层复制的区别仅与复合对象(即包含列表或类的实例等其他对象的对象)相关:

  • 浅层复制 构造一个新的复合对象,然后(在尽可能的范围内)将原始对象中找到的对象的 引用 插入其中。
  • 深层复制 构造一个新的复合对象,然后,递归地将在原始对象里找到的对象的 副本 插入其中。

制作字典的浅层复制可以使用 dict.copy() 方法,而制作列表的浅层复制可以通过赋值整个列表的切片完成,例如,copied_list = original_list[:]

python中的函数与变量命名

  • 单前导下划线:弱“内部使用”标志。例如 from M import 不会导入以下划线开头的对象。一般用于模块中的”私有”定义的命名。from module import * 语句用于加载模块中的所有名称,要控制导入的名称,一种方法是定义列表__all__,只有在__all__中的名称才能通过*导入,另一种方法就是以单下划线开头命名定义了,这种定义不会被导入。

  • 单后置下划线:按惯例使用避免与Python关键字冲突,例如。Tkinter.Toplevel(master, class_=’ClassName’)

  • 双前导下划线:用于数据的封装,实现数据和方法的隐藏,机制是通过自动”变形”实现的,类中所有以双下划线开头的名称__name都会自动变为 _类名__name 的新名称:当命名类属性,调用时名称改编(类FooBar中,__boo变成 FooBar__boo)。

  • 前导和后置都是双下划线:一般用于特殊方法的命名,用来实现对象的一些行为或者功能,比如__new__()方法用来创建实例,__init__()方法用来初始化对象

    例如:__init____import____file__。不要创造这样的名字;仅像文档中那样使用他们。

yield函数

带有 yield 的函数在 Python 中被称之为 generator(生成器)

继承

在python中继承中的一些特点:

  • 1、如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法。详细说明可查看: python 子类继承父类构造函数说明
  • 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
  • 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

如果在继承元组中列了一个以上的类,那么它就被称作”多重继承” 。

实例变量与类变量

一般情况下,类变量可以用类名或者self的形式访问。当 self.类变量 被重新赋值时,它的值就发生了变化,但类变量的值不会随之变化。方法内的局部变量会屏蔽掉类变量和实例变量。类变量是所有实例共享的,而实例变量只属于对象自己,每个实例的实例变量可以有不同的值。

  • 1、类变量可以用 类名.类变量self.类变量 两种方式访问,后者一般情况不建议使用。
  • 2、类变量是所有对象所共享的,无论任何时候都建议用类名的方式访问类变量。
  • 3、实例变量在类内部用 self 访问,在类外部用实例名访问。
  • 4、类变量通过 self 访问时则被转化为实例变量,被绑定到特定的实例上,其值会屏蔽掉类变量。
  • 5、通过对实例变量(self)的形式对类变量重新赋值后,类变量的值不随之变化。
  • 6、方法内的局部变量会屏蔽掉类变量和实例变量。
  • 7、同一实例变量在不同的实例中可能拥有不同的值。

函数传参

位置参数:两个参数的顺序必须一一对应,且少一个参数都不可以

关键字参数:用于函数调用,通过“键-值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。

默认参数:用于定义函数,为参数提供默认值,调用函数时可传可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)

不定长参数:定义函数时,有时候我们不确定调用的时候会传递多少个参数(不传参也可以),只能作为最后一个位置参数出现,。此时,可用两种方式:

包裹位置参数

1
def func(arg1,*args):

*args,加了星号(*)的变量名会存放所有未命名的变量参数。我们传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。

包裹关键字参数

1
2
3
def func(arg1,arg2,**kargs):
....
# func(1, 2, c=3,d=4)

**args是一个字典(dict),收集所有关键字参数

解包裹参数:

1
2
3
4
5
def print_hello(name, sex):
print name, sex

args = ('tanggu', '男')
print_hello(*args)

__new__()方法

object.``__new__(cls[, ])

调用以创建一个 cls 类的新实例。__new__() 是一个静态方法 (因为是特例所以你不需要显式地声明),它会将所请求实例所属的类作为第一个参数。其余的参数会被传递给对象构造器表达式 (对类的调用)。__new__() 的返回值应为新对象实例 (通常是 cls 的实例)。

典型的实现会附带适宜的参数使用 super().__new__(cls[, ...]),通过超类的 __new__() 方法来创建一个类的新实例,然后根据需要修改新创建的实例再将其返回。

If __new__() is invoked during object construction and it returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to the object constructor.

如果 __new__() 未返回一个 cls 的实例,则新实例的 __init__() 方法就不会被执行。

__new__() 的目的主要是允许不可变类型的子类 (例如 int, str 或 tuple) 定制实例创建过程。它也常会在自定义元类中被重载以便定制类创建过程。

__init__()方法

在实例 (通过 __new__()) 被创建之后,返回调用者之前调用。其参数与传递给类构造器表达式的参数相同。一个基类如果有 __init__() 方法,则其所派生的类如果也有 __init__() 方法,就必须显式地调用它以确保实例基类部分的正确初始化;例如: super().__init__([args...]).

因为对象是由 __new__()__init__() 协作构造完成的 (由 __new__() 创建,并由 __init__() 定制),所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError

python包中的__init__.py

作用:

  • init.py的第一个作用就是package的标识,

  • 如果没有该文件,该目录就不会认为是package。

  • 模糊导入中的*中的模块是由__all__来定义的,__init__.py的另外一个作用就是定义package中的__all__,用来模糊导入,也就是

1
from    moduleName    import *

__all__不会影响精确导入

if __name__ == '__main__'

1
2
if __name__ == '__main__':
main()

要知道这行代码的作用,我们首先要知道**__name__的作用,作为 Python 的内置变量,__name__**变量(前后各有两个下划线)还是挺特殊的。它是每个 Python 模块必备的属性,但它的值取决于你是如何执行这段代码的。

当你直接执行一段脚本的时候,这段脚本的 **__name__**变量等于 __main__,当这段脚本被导入其他程序的时候,__name__ 变量等于脚本本身的名字。

一个Python源码文件(.py)除了可以被直接运行外,还可以作为模块(也就是库),被其他.py文件导入。不管是直接运行还是被导入,.py文件的最顶层代码都会被运行

一个较好的解释

with关键字

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。

with 语句实质是上下文管理。

  • 1、上下文管理协议。包含方法__enter__() __exit__(),支持该协议对象要实现这两个方法。
  • 2、上下文管理器,定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。
  • 3、进入上下文的时候执行__enter__方法,如果设置as var语句,var变量接受__enter__()方法返回值。
  • 4、如果运行时发生了异常,就退出上下文管理器。调用管理器__exit__方法。

(1)紧跟with后面的语句被求值后,返回对象的“–enter–()”方法被调用,这个方法的返回值将被赋值给as后面的变量;
(2)当with后面的代码块全部被执行完之后,将调用前面返回对象的“–exit–()”方法。
with工作原理代码示例:

Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式,提高了易用性。with 语句使代码更清晰、更具可读性, 它简化了文件流等公共资源的管理。在处理文件对象时使用 with 关键字是一种很好的做法。

使用实例: with open('read.txt') as file1

python重载运算符

参考:Python 正确重载运算符

isinstance() 与 type()

isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。

isinstance() 与 type() 区别:

  • type() 不会认为子类是一种父类类型,不考虑继承关系。
  • isinstance() 会认为子类是一种父类类型,考虑继承关系。

如果要判断两个类型是否相同推荐使用 isinstance()。

1
isinstance(object, classinfo)

参数:

  • object – 实例对象。
  • classinfo – 可以是直接或间接类名、基本类型或者由它们组成的元组。

返回值:

如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。。

协程,aysnc与await


协程:

协程是子例程的更一般形式。 子例程可以在某一点进入并在另一点退出。 协程则可以在许多不同的点上进入、退出和恢复。 它们可通过 async def 语句来实现,协程是一种运行在用户态的轻量级线程,协程拥有自己的上下文和栈,在调度切换的时候会将寄存器上下文和栈保存在其他地方,等切回来的时候再恢复。

协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。 一个程序可以包含多个协程,可以对比与一个进程包含多个线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。 协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

协程 通过 async/await 语法进行声明,是编写 asyncio 应用的推荐方式

  • async用来声明一个函数为异步函数,异步函数的特点就是能在函数执行过程中被挂起,去执行其他异步函数,等挂起条件消失后再回来执行。
  • await作用 await用来声明程序挂起。await后面只能跟异步程序或有__await__属性的对象。如果一个对象可以在 await 语句中使用,那么它就是 可等待 对象。许多 asyncio API 都被设计为接受可等待对象。可等待 对象有三种主要类型: 协程, 任务Future.
    • await只能放在async修饰的函数里面使用;
    • await后面必须要跟着一个协程对象或者Awaitable;
    • await的目的是等待协程控制流的返回;
    • 实现暂停并挂起函数的操作的是yield;

要真正运行一个协程,asyncio 提供了三种主要机制:

  • asyncio.run() 函数用来运行最高层级的入口点 “main()” 函数 (参见上面的示例。)
  • 等待一个协程
  • asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。

等待 wait( )方法:

coroutine asyncio.``wait(aws, ***, timeout=None, return_when=ALL_COMPLETED)

并发地运行 aws 可迭代对象中的 可等待对象并进入阻塞状态直到满足 return_when 所指定的条件。

aws 可迭代对象必须不为空。

返回两个 Task/Future 集合: (done, pending)

用法:

1
done, pending = await asyncio.wait(aws)

如指定 timeout (float 或 int 类型) 则它将被用于控制返回之前等待的最长秒数。

请注意此函数不会引发 asyncio.TimeoutError。当超时发生时,未完成的 Future 或 Task 将在指定秒数后被返回。

wait_for() 不同,wait() 在超时发生时不会取消可等待对象。


future对象:

协程中更底层的对象:future对象,一般不会直接使用,它是task类的基类,task一部分功能是future提供的,其是更低级的接口,帮助我们去等待异步的结果。例如res=await task1 ,等结果是由future对象来创建的,future对象内部封装了一个_state的值,维护着状态,如果变成finished,就不再等待,而是往后执行,task对象继承future,task对象内部await结果的处理是基于Future对象进行处理的。

asyncio参考官方文档:用 asyncio 开发 — Python 3.10.2 文档

事件循环参考官方文档: 事件循环 — Python 3.11.0a0 文档

协程与任务参考官方文档:协程与任务 — Python 3.10.2 文档