文章目录
python学习的第二十天:第三周总结
函数
对函数的初步理解
- 世界级的编程大师Martin Fowler先生曾经说过:“代码有很多种坏味道,重复是最坏的一种!”
- 函数的作用是封装相对独立且会重复使用的代码,优化程序结构
- 通过函数可以对程序进行重构,所谓重构,是在不影响代码执行结果的前提下对代码的结构进行调整。
- 函数通过def构建,通过return返回值,通过""""""进行函数内的注释
- 如果函数中没有
return
语句,那么函数默认返回代表空值的None
函数模块的使用方法
-
如果要使用其他文件(模块)中定义的函数
方法一:可以通过import导入模块,然后通过"模块名.函数名"的方式调用函数;
方法二:直接从模块中导入函数 —> “from 模块 import 函数” —> 直接通过函数名调用函数 -
import导入函数、模块时,可以使用as关键字(alias)进行别名
-
做工程化项目开发时,如果项目中的代码文件非常多,我们可以使用"包"(package)来管理"模块"(module),
再通过模块来管理函数,包其实就是一个文件夹,而模块就是一个Python文件,通过这种方式就可以很好的解决
大型项目团队开发中经常遇到的命名冲突的问题。 -
Python中的from、import、as关键字就是专门用来处理包和模块导入的操作的。
-
定义函数时,写在前面的参数称为位置参数,调用函数传递参数时,只需要对号入座
写在后面的参数称为命名关键字参数,调用函数传递参数时,必须要写成"参数名=参数值"的形式
调用函数传递参数时,可以给参数带上名字,这种参数称为关键字参数
函数的进阶
-
arguments —> args —> 参数
位置参数 —> positional argument
关键字参数 —> keyword argument —> 参数名=参数值
关键字参数一定是在位置参数的后面
-
Python中的函数是一等函数,满足条件:
- 函数可以作为函数的参数
- 函数可以作为函数的返回值
- 函数可以赋值给变量
-
如果把函数作为函数的参数或者返回值,这种玩法通常称之为高阶函数。
通常使用高阶函数可以实现对原有函数的解耦合操作。 -
运算 - operate,运算符 - operator
-
Lambda函数 —> 没有名字而且一句话就能写完的函数,唯一的表达式就是函数的返回值
-
设计函数的时候,一定要注意函数的无副作用性(调用函数不影响调用者)
函数的递归
- 函数如果直接或间接的调用了自身,这种调用称为递归调用。
- 不管函数是调用别的函数,还是调用自身,一定要做到快速收敛。
- 在比较有限的调用次数内能够结束,而不是无限制的调用函数。
- 如果一个函数(通常指递归调用的函数)不能够快速收敛,那么就很有可能产生下面的错误
RecursionError: maximum recursion depth exceeded
最终导致程序的崩溃。 - 递归函数的两个要点:
- 递归公式(第n次跟第n-1次的关系)
- 收敛条件(什么时候停止递归调用)
面向对象编程
对面向对象编程的基础理解
-
指令式编程 —> 面向过程(函数)编程 —> 程序比较简单的时候没有任何毛病
编程范式(程序设计的方法论):面向对象编程 / 函数式编程
-
对象:对象是可以接收消息的实体,面向对象编程就是通过给对象发消息达到解决问题的目标。
对象 = 数据 + 函数(方法)—> 对象将数据和操作数据的函数从逻辑上变成了一个整体。
- 一切皆为对象
- 对象都有属性和行为
- 每个对象都是独一无二的
- 对象一定属于某个类
-
类:将有共同特征(静态特征和动态特征)的对象的共同特征抽取出来之后得到的一个抽象概念。
-
简单的说,类是对象的蓝图(模板),有了类才能够创建出这种类型的对象。
-
面向对象编程:
- 定义类 —> 类的命名使用驼峰命名法(每个单词首字母大写)
- 数据抽象:找到和对象相关的静态特征(属性)—> 找名词
- 行为抽象:找到和对象相关的动态特征(方法)—> 找动词
- 造对象
- 发消息
面向对象编程过程中的特殊技巧
-
我们在类里面写的函数,通常称之为方法,它们基本上都是发给对象的消息。但是有的时候,我们的消息并不想发给对象,而是希望发给这个类(类本身也是一个对象),这个时候,我们可以使用静态方法或类方法:
静态方法 - 发给类的消息 —> @staticmethod —> 装饰器
类方法 - 发给类的消息 —> @classmethod —> 装饰器 —> 第一个参数(cls)是接收消息的类 -
-
魔术方法(魔法方法)—> 有特殊用途和意义的方法
- init —> 初始化方法,在调用构造器语法创建对象的时候会被自动调用
- str —> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用
-
repr —> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用
—> representation - lt —> 在使用 < 运算符比较两个对象大小时会自动调用
-
如果一个变量的取值只有有限个选项,可以考虑使用枚举类型。
Python中没有定义枚举类型的语法,但是可以通过继承Enum类来实现枚举类型。
结论1:枚举类型是定义符号常量的最佳选择
面向对象编程的四大支柱
-
抽象(abstraction):提取共性(定义类就是一个抽象过程,需要做数据抽象和行为抽象)。
-
封装(encapsulation):把数据和操作数据的函数从逻辑上组装成一个整体(对象)。
隐藏实现细节,暴露简单的调用接口。
-
继承(inheritance):扩展已有的类创建新类,实现对已有类的代码复用。
-
多态(polymorphism):给不同的对象发出同样的消息,不同的对象执行了不同的行为。
方法重写:子类对父类已有的方法,重新给出自己的实现版本,这个过程叫做方法重写(override)。
在重写方法的过程中,不同的子类可以对父类的同一个方法给出不同的实现版本,那么该方法在运行时就会表现出多态行为。
两个类之间的关系
-
is-a关系:继承 —> 从一个类派生出另一个类
a student is a person
a teacher is a person
-
has-a关系:关联 —> 把一个类的对象作为另外一个类的对象的属性
a person has an identity card
a car has an engine.
- (普通)关联
- 强关联:整体和部分的关联,聚合和合成
-
use-a关系:依赖 —> 一个类的对象作为另外一个类的方法的参数或返回值
a person use a vehicle.
关于继承
-
继承:对已有的类进行扩展创建出新的类,这个过程就叫继承。
提供继承信息的类叫做父类(超类、基类),得到继承信息的类称为子类(派生类)。 -
继承是实现代码复用的一种手段,但是千万不要滥用继承。
-
子类直接从父类继承公共的属性和行为,再添加自己特有的属性和行为,
所以子类一定是比父类更强大的,任何时候都可以用子类对象去替代父类对象。 -
Python中的继承允许多重继承,一个类可以有一个或多个父类。
但如果不是必须使用多重继承的场景下,请尽量使用单一继承。 -
如果要限制一个类的对象只能拥有某些属性,可以在类中使用__slots__魔法属性
class Student:
slots = (‘name’, ‘gender’)
hon中的继承允许多重继承,一个类可以有一个或多个父类。
但如果不是必须使用多重继承的场景下,请尽量使用单一继承。 -
如果要限制一个类的对象只能拥有某些属性,可以在类中使用__slots__魔法属性
class Student:
slots = (‘name’, ‘gender’)