一、函数
1、介绍
函数:组织好的、可重复使用的、用来实现单一或相关联功能的代码块,能提高代码的模块性和复用性。
函数分为内置函数和自定义函数
内置函数:

自定义函数:自定义函数就是你自己用def定义的、按需封装的代码块,用来执行特定任务并随时调用。
2、函数的定义
Python函数的定义包括对函数名、函数的参数与函数功能的描述,使用def关键字。
语法:

注意:

无参函数:

有参函数:

Python允许函数体为空的函数。
语法:

pass 是空语句,是为了保持程序结构的完整性,"这里先预留位置,回头再补上具体的代码实现"。
3、函数的调用
语法:函数名(实际参数列表)
①如果调用的是无参数函数,则实参列表省略。
②通常将函数定义和函数调用都放在一个程序文件中,然后运行程序文件。


嵌套调用
指在一个函数内部调用另一个函数,通过函数间的层层协作来完成复杂任务。

4、递归函数
(1)什么是递归
递归函数是指一个函数的函数体中又直接或间接地调用该函数本身的函数。

递归出口:停止递归调用的条件(基线条件),防止无限循环下去。
递归体:函数内部调用自身的那部分逻辑,负责把大问题分解成更小的同类子问题。
(2)举例子
①实例: 求n!的递归函数。



②实例: 求
的递归函数。


5、函数参数的传递

(1)当参数类型为固定数据类型(如整数、浮点数、字符串、元组等)时,类似 C++ 的值传递,在函数内部直接修改形参的值不会影响实参。
(2)当参数类型为可变数据类型(如列表、字典、集合等)时,类似 C++ 的引用传递。在函数内部使用下标或其他方式为其增加、删除元素或修改元素值时,修改后的结果是可以反映到函数之外的,即实参也会得到相应的修改。
可变和不可变数据类型:
-
不可变数据类型:创建后内容不能被修改(如整数、浮点数、字符串、元组),任何"修改"操作实际上会生成新对象。
-
可变数据类型:创建后内容可以被修改(如列表、字典、集合),修改时对象本身不变,只是内部元素变化。




6、参数的类型
(1)位置参数
调用函数时,实参和形参的顺序必须严格一致,并且实参和形参的数量必须相同。

(2)关键字参数
关键字参数的形式为:形参名=实参值
通过形式参数的名称来指示为哪个形参传递什么值,这可以跳过某些参数或脱离参数的顺序。(实参名来自形参的名字)

(3)默认值参数
默认值参数的形式为:形参名=默认值
注意:
(1)默认值参数必须出现在形参表的最右端。也就是说,第一个形参使用默认值参数后,它后面的所有形参也必须使用默认值参数,否则会出错。
(2)所有的位置参数必须在默认参数前,包括函数定义和调用

(4)可变长度参数
定义函数时不确定需要传递多少个参数,可以使用包裹传递:在形参名前面加*,用来接受任意多个实参并将其放在一个元组中。
元组可变长度形参:


在形参名前面加**,可以接受任意多个关键字=实参值 形式的实参。关键字参数和实参值参数被放入一个字典,分别作为字典的关键字和字典的值。
字典可变长度形参:


注意:可变长度参数永远放在参数的最后面。

(5)参数的解包裹传递
调用函数时,若函数接收的实参为元组或字典类型,可以对函数参数进行解包裹:
①使用*可以解压传递到函数中的元组、列表、字符串等类型,并按位置传递到函数入口参数中。
②使用**可以解压待传递到函数的字典,并按关键字传递到函数入口参数中。
⚠️注意:包裹和解包裹并不是相反操作,是两个相对独立的过程。
示例1:元组解包裹

示例2:字典解包裹

输出结果:

综合示例:求三角形面积,三边长从键盘输入
面积公式
,其中
。


7、变量的作用域
变量的作用域:可以理解为变量的作用范围,它决定了在代码的哪些位置可以访问该变量,超出其作用域范围则无法被引用。
①局部变量:在函数中定义的。
②全局变量:在函数外面、全局范围内定义的。
(1)什么是局部变量?
在一个函数体内或语句块内定义的变量称为局部变量,局部变量仅在定义它的函数体或语句块内部生效,离开该范围就无法使用,外部代码无权访问。



(2)什么是全局变量?
定义在函数体外的变量称为全局变量,全局变量定义在函数外部,在整个程序范围内都可访问。当全局变量与局部变量同名时,在函数内部优先访问局部变量(局部覆盖全局)。



(3)全局变量 - global关键字
在函数内部修改一个定义在函数外的变量时,须使用global关键字明确声明变量。在函数内部通过global关键字来声明或定义全局变量。

(4)"看不见"的字典
变量名:key
变量值:value
Pthon提供3个工具函数,来获取指定范围内的"变量字典":
①globals():全局
②locals():局部
③vars(Object):获取指定对象范围内所有变量组成的"变量字典",如果不传入Object参数,vars()和locals()作用完全相同。
⚠️注意:vars()只能传入具有__dict__属性的对象(如自定义类实例、模块、类本身),不能传入内置类型(如字典、列表、整数等)。


(5)globals()和locals()的区别和联系
locals():总是获取当前局部范围内所有变量组成的"变量字典",因此,在全局范围内(函数之外)调用 locals()函数,同样会获取全局范围内所有变量组成的"变量字典" 。
globals():它无论在哪儿,都获取全局范围。 获取的"变量字典"可被修改,不影响变量本身。
(6)局部变量屏蔽全局变量的解决方法
有以下两个解决办法:
①通过globals()函数访问被遮蔽的全局变量。
②使用global语句来声明全局变量。
(7)nonlocal关键字
Python3.x引入了nonlocal关键字,只要在内层函数中用nonlocal语句说明变量,就可以让解释器在外层函数中修改变量的值。


nonlocal和global 功能大致相似,区别只是 global 用于声明访问全局变量,而 nonlocal 用于声明访问当前函数所在函数内的局部变量。
8、函数嵌套定义
函数嵌套:python允许在函数中定义另外一个函数,定义在其他函数内部的函数称为内建函数,包含有内建函数的函数称为外部函数。

9、函数的返回值
return用于返回函数值并结束函数。可有多条但仅执行一条,执行后后续语句不再运行。无 return 时隐式返回 None。多返回值本质是元组。
使用函数嵌套:

直接使用内置sum函数:

结果:

10、函数作为对象赋值或传参
(1)函数赋值给变量
Python的函数也是一种值,即所有函数都是function对象,所以可以把函数赋值给变量,通过该变量来调用函数。

(2)函数作为另一个函数的形参


Python的本身也提供了一个map函数。


(3)函数作为另一个函数的返回值


(4)闭包
闭包就是能够读取其他函数内部变量的函数。
闭包特性:
①可以外部访问函数内部变量
②内部函数可以访问外层函数变量
③局部变量可以常驻内存

代码分析:外部函数 fout 内部定义了局部变量 x 和嵌套函数 fin,fin 引用了 x。当 fout 执行完毕并返回 fin 后,x 并没有被销毁,而是被 fin 携带保留下来。因此 result 实际是带有记忆的 fin 函数,调用 result(5) 时能访问到之前保留的 x=3,最终输出 8。
(5)装饰器
装饰器本质上是一个闭包函数,用于在不修改原函数代码的前提下,为其增加额外功能。
核心要点
-
本质:闭包函数,接收一个函数作为参数,返回一个新的函数对象
-
作用:在不改动原函数代码的情况下,动态增强或改变其功能
-
语法 :采用
@装饰器名的语法糖格式(如@classmethod、@property) -
常见应用场景:插入日志、性能测试、事务处理、缓存、权限校验等
为什么要使用装饰器?
在不修改被装饰对象的前提下为其添加新功能。
开放封闭原则
开放:指的是对拓展功能是开放的。(允许添加新功能)
封闭:指的是对修改源代码是封闭的。(不应改动已有代码)
工作原理

示例代码



代码执行顺序:
①执行funA(funB),输出"C语言中文网"、"python的学习"、"https://kecheng.com"。
②funB被赋值,值为"装饰器的返回值"。
③执行print(funB),输出"装饰器的返回值"。
11、lambda函数
形参和返回值:冒号前面是形参列表,冒号后面是返回值表达式
匿名函数:也称为lambda函数,用lambda语句创建的函数对象没有名称
定义形式:lambda 参数1\[,参数2,......,参数n]:表达式
lambda函数的定义与调用:将lambda语句作为对象赋值给变量,通过变量名进行调用


说明:
①lambda定义的是单行函数,省去函数定义过程,代码简洁。
②lambda语句可以包含多个参数。
③使用后立即释放,提高了性能。
④lambda语句中的表达式不能含有命令,且仅限一条表达式(避免滥用)。
(1)匿名函数作为函数返回值


(2)匿名函数作为序列或字典的元素
以列表为例,一般格式为:列表名=匿名函数1,匿名函数2,......,匿名函数n
调用方法:以序列或字典元素引用作为函数名来调用匿名函数。
调用格式为: 列表或字典元素引用(匿名函数实参)


总结:把匿名函数放进列表或字典里,然后用 [索引] 或 ["键名"] 取出来加括号 () 调用。
二、类和对象
1、面向对象的程序设计
(1)面向对象与面向过程
①面向过程
核心思想:采用自顶向下 的设计方法,将程序分解为若干个功能模块 ,每个模块用函数实现,按步骤顺序执行。
优点:极大降低了写程序的复杂度,只需按执行步骤堆叠代码即可。
缺点:一套流程解决一个问题,代码牵一发而动全身,扩展性差。
应用场景:需求一旦完成就很少改变的场景,如 Linux 内核、git、Apache HTTP Server 等。
②面向对象
核心思想:万物皆为对象 ,编程时尽可能模拟现实世界。任何一个动作的发生都存在一个支配该动作的实体 (对象),功能的实现就是各个对象发挥各自能力并协调调用的过程。
优点:解决了程序的扩展性,对单个对象修改会立刻反映到整个体系中。
缺点:可控性差,无法像面向过程那样精准预测处理流程与结果,程序由对象间交互解决问题,最终结果难以预判。
应用场景:需求经常变化的软件,主要集中在用户层,如互联网应用、企业内部软件、游戏等。
(2)采用面向对象的思想
第一步:分析哪些动作是由哪些实体发出的。
第二步:定义这些实体,为其增加相应的属性和功能。
第三步:让实体去执行相应的功能或动作。


(3)面向对象三大特征

2、类与对象
(1)什么是类和对象
对象
现实世界中客观存在的事物称为对象。任何对象都具有属性 (特征,用数据表示)和方法(行为,用程序代码实现)。对象由属性和方法共同组成。
类
类是具有相同属性和行为的一组对象的集合 ,为所有该类对象提供统一的抽象描述。对象是类的具体实例。
简而言之:类是对象的模板(抽象),对象是类的实例(具体)。
(2)类与对象的关系

类:具有相同特征的一类事物(人、狗、老虎)
对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
实例化:类➔对象的过程
(3)类的定义
①什么是类
类(class)是具有相同属性和行为的一组对象的集合,由3部分组成的:
类名:类名,大驼峰,单词之间无分隔符。
属性:一组数据,比如角色,性别等。
方法:允许进行操作的方法,比如走路。

②类与函数


③定义一个类

➊__init__ 方法(构造方法)
-
无需手动调用,在生成实例对象时自动执行。
-
作用是初始化新创建对象的属性。
-
若类中未定义
__init__,实例化时会自动调用默认的无参构造方法。
➋self 参数
-
代表当前类的实例,指向实例对象本身。
-
Python 规定:实例方法的第一个参数必须是实例对象本身 ,习惯命名为
self(非关键字,可改名,但强烈推荐使用self)。 -
调用实例方法时,无需手动传入
self,系统会自动传递。
④this指针与self
提示:self在功能上等同于C++的this指针,可以把self看作一个this指针。
区别:它们在功能上完全相同,都是指代当前实例;区别在于 Python 要求显式声明和使用,而 C++ 是隐式的。
(4)创建对象 -- 类的实例化

⚠️注意:在访问对象的方法时,实参要与除self以外的其他形参匹配。(实参与形参一一对应)

每次创建的对象,在内存中的地址是不相同的。
示例代码:
定义矩形类Rectangle,有三个方法:
(1)__init__方法:初始化长和宽
(2)getArea方法:返回矩形的面积
(3)getPerimeter方法:返回矩形的周长


3、属性和方法的访问控制

(1)类属性
类属性:定义在类中、方法之外的变量,属于类对象本身,用于记录与类整体相关的特征。
核心特点:被该类的所有实例对象所共享,在内存中只保留一个副本。类属性既可以通过类名直接访问,也可以通过实例名访问。

特殊的类属性:
①类名.name # 类的名字
②类名.doc # 类的文档字符串
③类名.base # 类的第一个父类
④类名.bases # 类所有父类构成的元组
⑤类名.dict # 类的字典属性
⑥类名.module # 类定义所在的模块
⑦类名.class # 实例对应的类
(2)实例属性
实例属性:在__init__构造函数中定义的属性,属于具体的实例对象,只能通过对象名访问。虽然也可以在类中其他方法里随意添加新属性,但不提倡这样做。
最佳实践:所有实例属性都应在__init__方法中集中定义和初始化,这样有助于清晰地管理类的属性结构,便于维护和修改。
总结:实例属性属于具体对象,最好在__init__中统一定义,通过对象名访问。
(3)方法的访问控制
实例方法:

类方法:

静态方法:

①实例方法
实例方法是类中默认定义的方法,必须通过实例化对象才能调用。
它的核心特征是:
-
至少包含一个
self参数,用于绑定调用该方法的实例对象(由 Python 自动完成绑定)。 -
通常通过实例对象调用,也可以使用类名调用,但需要手动为
self参数传入一个实例对象作为实参。
两个特殊的实例方法:
构造方法:init(self)
析构方法:del(self)
析构方法一般无需定义,当对象在内存中被释放时,自动触发执行。


②类方法
类方法是类对象拥有的方法,操作类级别的数据,用 @classmethod 装饰器标识,无需实例化即可调用。
核心特点:
-
第一个参数是
cls,代表类本身(由 Python 自动传入)。 -
可通过类名或实例名访问:
类名.方法名()或实例.方法名()。 -
主要作用:修改类属性、调用其他类方法。
-
应用场景:方法中只涉及静态属性(类属性)时使用。


实例属性 discount 的主要弊端:
-
无法统一管理:每个实例独立存储,修改折扣需逐一操作,效率低下。
-
数据一致性差:容易遗漏某些实例,导致同类商品折扣不一致。
-
内存浪费:每个实例重复存储相同的属性值。
-
维护成本高:批量修改需遍历所有实例,代码冗余。


关键点:
-
类属性
discount被所有实例共享,内存中只存在一份。 -
类方法
change_discount通过cls参数修改类属性,无需实例化即可调用。 -
实例方法
new_price通过Goods.discount访问类属性,所有实例统一使用当前折扣。
总结:共享数据 应定义为类属性,避免重复存储和逐一维护。
③静态方法
静态方法用 @staticmethod 装饰器标识,不需要 self 或 cls 参数,本质上是一个与类解耦的独立函数,只是被放在类的命名空间中。
核心特点:
-
无需
self或cls参数,与类和实例没有直接关联。 -
可通过类名或实例名访问:
类名.方法名()或实例.方法名()。 -
不能访问类属性或实例属性,功能等同于普通函数。
-
应用场景:方法逻辑与类本身无关,但功能上归属于该类(如工具函数、辅助计算等)。
与类方法的区别:
-
静态方法:既不使用实例属性,也不使用类属性,就是放在类里的普通函数。
-
类方法:不使用实例属性,只使用类属性,用于操作类级别的数据,第一个参数是
cls。


三、封装、继承和多态
1、封装
(1)什么是封装
封装:将属性和方法整合到一个类中,类是封装的载体。
核心要点:
①隐藏内部细节:用户无法直接查看或操作类内部的数据结构,只能通过类提供的公开方法进行访问。
②保护数据完整性:通过限制外部直接访问,避免内部数据被随意篡改,确保数据安全。
③提高可维护性:内部实现变更时,只要公开接口保持不变,外部代码不受影响,便于维护和扩展。


(2)私有属性
Python中的私有属性并非真正无法访问。在类中定义的私有属性(以双下划线__开头),类外访问时需加上_类名前缀即可访问。
核心要点
①命名重整:Python会将私有属性__attr自动重命名为_类名__attr,以实现"伪私有"。
②类外访问方式:通过实例._类名__私有属性名可以强行访问。
③本质:这是一种约定而非强制限制,体现了Python"大家都是成年人"的设计哲学。
总结:私有属性只是被"改名"了,知道规则后依然可以访问,并不存在真正的私有性。

间接访问方法1
为了更好的保存属性安全,即不能随意修改,一般的处理方式为:
➊将属性定义为私有属性(以两个下划线开头)
➋添加方法,间接访问私有变量。
说明:
◎python 私有属性只能在类内部访问,类外面访问会出错。
◎python 保护属性更多的是一种语法上的标识,用来提醒直接修改改对象时候要小心。


间接访问方法2 -- property
功能:property属性内部进行一系列的逻辑计算,最终返回计算结果。
property属性有两种方式:
①类属性方式,创建值为property对象的类属性
②在类的实例方法上应用@property装饰器
-- @property修饰获取的方法getter,方法名必须和属性名一样
-- @XXX.setter修饰设置值的方法setter,方法名必须和属性名一样
作用:在新式类中返回属性值。( 新式类:继承 object 的类)
语法:class property(fget\[, fset\[, fdel\[, doc]]])
●fget -- 获取属性值的函数
●fset -- 设置属性值的函数
●fdel -- 删除属性值函数
●doc -- 属性描述信息
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息
one、属性方式


two、property装饰器方式


(3)私有方法
Python默认的成员函数和成员变量都是公开的,在变量名或函数名前加上 "_ _"两个下划线,那么这个函数或变量就会为私有的了。 私有方法不能在类的外部调用,但可以在类内部访问私有方法。

2、继承
面向对象的编程带来的主要好处之一是代码的复用,实现这种复用的方法之一是通过继承机制。

说明:object类是Python中所有类的基类,如果定义一个类时没有指定继承哪个类,则默认继承object类。 子类可以继承父类的公有成员,但不能继承其私有成员。
(1)单继承

单继承:是指新建的类只继承一个父类
python
class 派生类名(基类名):
类体


在继承中,基类的构造方法(init()方法)不会被自动调用,它需要在其子类的构造方法中专门调用。 如果需要在子类中调用基类的方法,可以使用内置函数super()或者通过"基类名.方法名(参数)"的方式来实现。
方法一:使用super()


方法二:使用基类名直接调用


(2)多继承

类的多重继承:通过类的多重继承,一个子类就可以继承多个父类,并从多个父类中取得所有非私有方法。
python
class 派生类名(基类1, 基类2,...., 基类n):
类体
核心规则:在Python多继承中,若子类未定义某方法,则按父类在圆括号中的从左到右顺序依次搜索。即子类自己没有,就按父类声明顺序逐个查找。
关键要点:
●搜索路径:子类 → 从左到右的父类 → 父类的父类(遵循相同顺序)。
●实际机制:Python 通过 MRO(方法解析顺序) 算法(C3 线性化)确定精确搜索路径,可用 类名.__mro__ 查看。
●多继承冲突:当多个父类有同名方法时,左侧优先。



(3)重载和重写
重载:在Python中,只要方法名相同 就认为是同一个方法,后定义的同名方法会覆盖先定义的。在多继承中,先继承的父类同名方法会覆盖后继承的父类同名方法。Python语法上不支持传统意义上的重载,但可通过魔法方法或装饰器实现类似重载的效果。
重写:子类可以对从父类中继承过来的方法进行重新定义 ,从而使得子类对象表现出与父类对象不同的行为。
重载和重写的区别:重写 发生在子类和父类之间,子类会覆盖父类中同名且参数、返回类型都相同的方法,也称为方法覆盖。重载发生在同一个类内部,指多个同名函数共存,但这些函数的参数类型或参数个数不同,返回类型也可以不同。Python语法上不支持重载。
Python不需要重载的原因:Python原生语法已经天然支持参数类型灵活 和参数个数灵活,所以不需要通过方法重载来手动实现这些效果。


3、多态
(1)什么是多态
多态:同一名字的方法产生了多个不同的行为,也就是不同的对象收到相同的消息时产生不同的行为方式。简而言之,多态就是一个对象同样的方法,在不同场景有不同的行为。
多态的体现:
在python中,很多地方都可以提现多态的特性,如内置函数len(),len函数不仅可以计算字符串的长度,还可以计算列表、元组等对象中的数据个数,在运行时通过参数类型确定其具体的计算过程,正是多态的一种体现。
(2)多态的应用场景
①对象所属的类之间没有继承关系


②对象所属的类之间有继承关系(应用更广)


(3)多态的特点
●只关心对象的实例方法是否同名,不关心对象所属的类型。
●对象所属的类之间,继承关系可有可无。
●多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强。
●多态是调用方法的技巧,不会影响到类的内部设计。
拓展:Java中的多态体现为父类引用指向子类对象,表现形式明确。Python虽然也支持多态,但由于变量不需要声明类型,不存在父类引用指向子类对象这种典型写法,所以多态在Python中表现得不那么明显。因此,在Python中刻意强调多态的意义并不大。
(4)派生
子类可以在继承父类的基础上定义新的属性 ,也可以定义与父类同名的属性 来覆盖父类的属性。这些重新定义或新增的属性都属于子类自己(子类独有的 ),不会影响父类。当子类定义了与父类同名的属性时,调用该属性将以子类自己的定义为准。子类也因此被称为派生类。
4、动态性
(1)python的动态性
Python是动态语言,特点就是可以动态增加和修改类和对象的属性和方法。
说明: __slots__只对类的实例起作用。 并不限制通过类来动态添加属性或方法,对该类派生出来的子类也不起作用。


(2)使用type()函数动态创建类
type() 函数的语法格式有 2 种:
①type(obj)
②type(name, bases, dict)
第一种语法格式用来查看某个变量(类对象)的具体类型。
第二种语法格式用来创建类,其中 name 表示类的名称;bases 表示一个元组,其中存储的是该类的父类;dict 表示一个字典,用于表示类内定义的属性或者方法。




(3)metaclass动态修改类定义
metaclass是type的子类,通过重写type的__call__方法可以改变类的创建行为。它在Python中功能极其强大,但争议也很大,有人认为它无所不能,也有人认为它容易导致滥用。即使是硅谷一线大厂,使用metaclass也需要特批。真正深入理解它的开发者极少,在实际工作中应当谨慎使用。
四、模块
1、模块
(1)什么是模块
模块是一个包含所有定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。

(2)模块的分类
①内置模块
内置模块:Python内置标准库中的模块,也是Python的官方模块,可直接导入程序。在命令行下运行$ pydoc modules即可查看。
②第三方模块
第三方模块:由非官方制作发布,供给大众使用的Python模块,在使用之前需要先自行安装。在命令行下运行 pip install SomePackage即可安装第三方模块; pip list 显示已安装的模块
③自定义模块
自定义模块是用户在程序编写中自行编写,存放功能性代码的.py文件。
(3)模块的使用
Python程序通常由一个主程序以及多个模块组成。
下图描述了一个由三个程序文件a.py、b.py和c.py.py组成的Python程序,其中a.py是主程序,b.py和c.py是模块,箭头指向代表了程序之间的相互调用关系。模块b.py和c.py一般不能直接执行,该程序的执行只能从主程序a.py开始。

●导入某个模块:
○import module1,mudule2,...
○使用模块中的某个函数: 模块名.函数名

●导入某个模块中的函数:
○from 模块名 import 函数名1,函数名2,...
○使用模块中的某个函数: 函数名

●导入某个模块中的所有函数:
○from 模块名 import *
○使用模块中的某个函数: 函数名

●导入模块并取别名:
○import 模块名 as 新名字

注意事项:

(4)自定义模块
示例代码:

输出结果:

2、模块的有条件执行
(1)__name__属性
●_ name _是python的一个内置类属性,它存储模块的名称。
●python的模块既可以被调用,也可以独立运行。而被调用时_ name 存储的是py文件名(模块名称),独立运行时存储的是" main _"。
●它的作用主要就是用来区分当前模块是独立运行还是被调用。
(2)示例代码



if name == "main": 的作用是判断当前脚本是否作为主程序直接运行,如果是,则执行该代码块;如果是被其他模块导入,则不执行,从而让代码既可以被测试,又可以被安全地导入使用。
此时main.py为主程序,swap模块的if name == "main":条件不符,不运行这个分支

此时swap.py是主程序,swap模块的if name == "main":条件符合,运行这个分支

3、Python包结构
(1)包的概念
如果有两个相同名字的模块,应该如何防止命名冲突?
为了更好地管理多个模块源文件,Python 提供了包的概念。 简单来说,包就是文件夹,但该文件夹下必须存在 _ init _.py 文件。
_ init _.py文件:内容是空的,它的作用是告诉解释器,这是一个Python Package。 从逻辑上看,包的本质依然是模块。

(2)numpy包
Python 安装了 numpy 模块之后,可以在 Python 安装目录的 Lib\site-packages 目录下找到一个 numpy 文件夹,它就是前面安装的 numpy 模块(其实是一个包)。
numpy 包(也是模块)下既包含了 matlib.py 等模块源文件,也包含了 core 等子包(也是模块)。这正对应了我们刚刚介绍的:包的本质依然是模块,因此包又可以包含包。
(3)定义包
定义包主要有两步:
①创建一个文件夹,该文件夹的名字就是该包的包名。
②在该文件夹内添加一个 _ init _.py 文件即可。
●包的本质就是模块,因此导入包和导入模块的语法完全相同,只是需要在模块前加上包名!
●包的导入仍使用 import 、 from ... import 语句,使用 "圆点模块名" 的结构化模块命名空间。
●与模块类似的是,包被导入之后,会在包目录下生成一个 pycache 文件夹,并在该文件夹内为包生成一个 init.cpython-36.pyc 文件。

(4)导入包


4、常用模块
(1)第三方模块的安装
pip 是 Python 包管理工具,该工具提供了对Python 包的查找、下载、安装、卸载的功能。
可以通过以下命令来判断是否已安装:

(2)常用的第三方库安装


(3)示例代码
安装第三方库:wordcloud

(4)OS库
os库提供通用的、基本的操作系统交互功能。os库是Python标准库,包含几百个函数 常用路径操作、进程管理、环境参数等几类。
①路径操作:os.path子库,处理文件路径及信息
②进程管理:启动系统中其他程序
③环境参数:获得系统软硬件信息等环境参数
♞路径操作






♞进程管理



♞环境参数



(5)random模块
random是python的重要标准模块之一,用于伪随机数生成,所用的算法是梅森旋转算法。
(1) random.random() #用于生成一个0到1的随机浮点数:0<= n < 1.0
(2) random.uniform(a,b) #用于生成一个指定范围内的随机浮点数
(3) random.randint(a, b) #用于生成一个指定范围内的整数。
(4) random.randrange(start, stop, step) #从指定范围内,按指定基数递增的集合中获取一个随机数
(5) random.choice(sequence) #从序列中获取一个随机元素
(6) random.shuffle(x, random) #用于将一个列表中的元素打乱
(7) random.sample(sequence, k) #从指定序列中随机获取指定长度的片断并随机排列
