属性和方法
魔术方法
Python中的魔术方法(Magic Methods)是一种特殊的方法,它们以双下划线开头和结尾,例如`__init__`,`__str__`,`__add__`等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。
常用的Python魔术方法
1. `__init__(self, ...)`: 初始化对象,通常用于设置对象的属性。
2. `__str__(self)`: 定义对象的字符串表示形式,可通过`str(object)`或`print(object)`调用。例如,您可以返回一个字符串,描述对象的属性。
3. `__repr__(self)`: 定义对象的“官方”字符串表示形式,通常用于调试。可通过`repr(object)`调用。
4. `__len__(self)`: 定义对象的长度,可通过`len(object)`调用。通常在自定义容器类中使用。
5. `__getitem__(self, key)`: 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,`object[key]`。
6. `__setitem__(self, key, value)`: 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,`object[key] = value`。
7. `__delitem__(self, key)`: 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,`del object[key]`。
8. `__iter__(self)`: 定义迭代器,使对象可迭代,可用于`for`循环。
9. `__next__(self)`: 定义迭代器的下一个元素,通常与`__iter__`一起使用。
10. `__add__(self, other)`: 定义对象相加的行为,使对象可以使用`+`运算符相加。例如,`object1 + object2`。
11. `__sub__(self, other)`: 定义对象相减的行为,使对象可以使用`-`运算符相减。
12. `__eq__(self, other)`: 定义对象相等性的行为,使对象可以使用`==`运算符比较。
13. `__lt__(self, other)`: 定义对象小于其他对象的行为,使对象可以使用`<`运算符比较。
14. `__gt__(self, other)`: 定义对象大于其他对象的行为,使对象可以使用`>`运算符比较。
15. `__call__(self, other)` 是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。
封装 enclosure
封装是指隐藏类的实现细节,让使用者不用关心这些细节;
封装的目的是让使用者通过尽可能少的方法(或属性)操作对
Python的封装是假的(模拟的)封装
强行访问私有:实例._类名__方法名()
私有属性和方法
python类中以双下划线(`__`)开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用方法来进行访问和修改
以`__`开头的属性为类的私有属性,在子类和类外部无法直接使用
以`__`开头的方法为私有方法,在子类和类外部无法直接调用
多态 polymorphic
字面意思"多种状态"
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
状态:
静态(编译时状态)
动态(运行时状态)
多态说明:
多态调用的方法与对象相关,不与类型相关
Python的全部对象都只有"运行时状态(动态)", 没有"C++语言"里的"编译时状态(静态)"
方法重写
函数重写
在自定义类内添加相应的方法,让自定义类创建的实例像内建对象一样进行内建函数操作
对象转字符串函数重写
str() 函数的重载方法:
`def __str__(self)`
如果没有 `__str__(self)` 方法,则返回repr(obj)函数结果代替
内建函数重写
__abs__ abs(obj) 函数调用
__len__ len(obj) 函数调用
__reversed__ reversed(obj) 函数调用
__round__ round(obj) 函数调用
运算符重载
运算符重载是指让自定义的类生成的对象(实例)能够使用运算符进行操作
作用
让自定义类的实例像内建对象一样进行运算符操作
让程序简洁易读
对自定义对象将运算符赋予新的运算规则
重载说明
运算符重载方法的参数已经有固定的含义,不建议改变原有的意义
二元运算符重载方法格式
def __xxx__(self, other): ....
super函数
是用于调用父类(超类)的一个方法。
super()是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
语法:
在子类方法中可以使用super().add()调用父类中已被覆盖的方法
可以使用super(Child, obj).myMethod()用子类对象调用父类已被覆盖的方法
super().__init__()
`super().__init__()` 是 Python 中用于调用父类(基类)构造函数的一种方式。
它通常用于子类的构造函数中,以确保父类的构造函数被正确调用和初始化。
注释
Parent 类
定义了一个构造函数 `__init__()`,在构造函数中打印了一条消息,并初始化了一个属性 `parent_attribute`。
Child 类
继承自 `Parent` 类。
在其构造函数 `__init__()` 中,首先调用了 `super().__init__()`。这行代码会调用 `Parent` 类的构造函数,确保 `Parent` 类的初始化逻辑被执行。
然后打印了一条消息,并初始化了一个属性 `child_attribute`。
实例化 Child 类
创建 `Child` 类的实例时,首先执行 `Parent` 类的构造函数,打印 "Parent class constructor called",然后执行 `Child` 类的构造函数,打印 "Child class constructor called"。
Python迭代器与生成器
迭代器
什么是迭代器
迭代器是访问可迭代对象的工具
迭代器是指用 iter(obj) 函数返回的对象(实例)
迭代器可以用next(it)函数获取可迭代对象的数据
迭代器函数iter和next
iter(iterable)
从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象
next(iterator)
从迭代器iterator中获取下一个记录,如果无法获取一下条记录,则触发 StopIteration 异常
迭代器说明
迭代器只能往前取值,不会后退
用iter函数可以返回一个可迭代对象的迭代器
迭代器的用途
迭代器对象能用next函数获取下一个元素
生成器
什么是生成器
生成器是在程序运行时生成数据,与容器不同,它通常不会在内存中保留大量的数据,而是现用现生成。
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
每次使用 yield 语句生产一个值后,函数都将暂停执行,等待被重新唤醒。
yield 语句相比于 return 语句,差别就在于 yield 语句返回的是可迭代对象,而 return 返回的为不可迭代对象。
然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。
生成器可以用算法动态的生成数据
生成器有两种
生成器函数
含有yield 语句的函数是生成器函数,此函数调用回返回一个生成器对象,生成器也是可迭代对象
yield 语句的语法
yield 表达式
生成器表达式
语法:
( 表达式 for 变量 in 可迭代对象 [if 真值表达式]) ps:[] 内容代表可以省略
用推导式的形式创建一个生成器
python 函数式编程
定义:用一系列函数解决问题。
函数可以赋值给变量,赋值后变量绑定函数
允许将函数作为参数传入另一个函数
允许函数返回一个函数。
**总结**
什么时候使用函数式编程思想?
很多的逻辑或者说核心点是不变的,大多数就是一致的,这个时候我们就可以使用函数式编程思想,可以很好的去定位这个逻辑【函数 式编程思想相对于面向对象编程思想,它更接近于算法】。
函数式编程思想替代了面向对象思想?
如果需求中存在多个逻辑变化点时,可以使用类来进行,因为面向对象中存在继承、重写。而函数式编程思想则是将变化点提取到函数 中,实现简单的逻辑。
函数作为参数
将核心逻辑传入方法体,使该方法的适用性更广。
lambda 表达式
定义:是一种匿名函数
作用:
作为参数传递时语法简洁,优雅,代码可读性强。
随时创建和销毁,减少程序耦合度。
# 定义: 变量 = lambda 形参: 方法体 # 调用: 变量(实参)
形参没有可以不填
方法体只能有一条语句,且不支持赋值语句。
内置高阶函数
定义:将函数作为参数或返回值的函数。
map(函数,可迭代对象)
使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
filter(函数,可迭代对象)
根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
sorted(可迭代对象, key=函数, reverse=True)
排序,返回值为排序后的列表结果。
max(可迭代对象, key = 函数)
根据函数获取可迭代对象的最大值。
min(可迭代对象,key = 函数)
根据函数获取可迭代对象的最小值。
函数作为返回值
闭包 closure
闭包是指引用了此函数外部嵌套函数的变量的函数
闭包就是能够读取其他函数内部变量的函数。只有函数内部的嵌套函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数,同时这个函数又引用了外部的变量“。
在本质上,闭包是将内部嵌套函数和函数外部的执行环境绑定在一起的对象。
必须满足以下三个条件
必须有一个内嵌函数
内嵌函数必须引用外部函数中变量
外部函数返回值必须是内嵌函数。
全局变量和局部变量的区别
全局变量
一直存在,谁都可以访问和修改
局部变量
只是在调用时存在,只能在函数内部进行访问和修改
闭包的优缺点
优点
1. 逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑而单独编写额外逻辑。
2. 方便调用上下文的局部变量。
3. 加强封装性,是第2点的延伸,可以达到对变量的保护作用。
注意点(缺点)
1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值
装饰器 decorators(专业提高篇)
什么是装饰器
装饰器是一个函数,主要作用是来用包装另一个函数或类
装饰器的作用
在不修改被装饰的函数的源代码,不改变被装饰的函数的调用方式的情况下添加或改变原函数的功能。
函数装饰器的语法
def 装饰器函数名(fn): 语句块 return 函数对象 @装饰器函数名 <换行> def 被装饰函数名(形参列表): 语句块
用函数装饰器替换原函数myfun
def mydeco(fn): fn() print("装饰器函数被调用了,并返回了fx") def fx(): print("fx被调用了") # return fn() return fx @ mydeco def myfun(): print("函数myfun被调用") myfun() myfun()
实际上发生的
1. `myfun`函数作为参数传递给了`mydeco`装饰器。
2. 在`mydeco`内部,首先调用了`fn()`,即此时调用了`myfun`函数,产生了输出:"函数myfun被调用"。
3. 接着,打印了"装饰器函数被调用了,并返回了fx"。
4. 然后,`mydeco`装饰器返回了新的函数`fx`。
基本装饰器
有参数的函数装饰器(在myfunc外加了一层)
带参数的装饰器
带参数的装饰器需要三层函数,def wrapper(args, kwargs) 传入的是被修饰的函数的参数。