黑马程序员学Python——导入模块与继承问题

本文主讲:Python导入模块的几种方式及其注意事项、单继承与多继承、property装饰的使用、魔法属性与魔法方法、with上下文方式

检测字符串文件的后缀【重点】

怎么检测文件(字符串)的后缀!

关键字:endswith

语法:文件字符串.endswith(“后缀”)

注意事项:

1:后缀要加上. 例如 .py .txt

2:文件字符串.endswith(“后缀”)返回的是一个布尔值,是括号里面的后缀则返回True,不是括号里面的后缀返回False

图示:

image-20211012184426752

import导入模块路径【重点】

如何使用模块内的变量?

语法:模块名.变量名

实例:print(moudle.name) 即可打印 moudle 模块内name变量的值

注意事项:不仅可以使用模块内的函数以及类还可以使用变量等其他一切资源!

如何查看 python 解释器寻找模块所在路径的方法

关键字:sys.path

语法:

1
2
import sys
print(sys.path)

注意:sys.path是一个列表,里面存放着 python 解释器查找模块的所有路径

演示:

如何利用 import 导入指定路径的模块

第一步:查看目标模块的路径

image-20211012184507006

第二步:将目标模块路径加到 python 查找模块路径的列表内即可!

添加方法:

1:列表.append(待添加数据)

2:列表.insert(位置,待添加数据)

注意事项:

1:向 sys.path 列表(python查找模块的路径列表)内添加完模块目标路径之后,程序重新运行后,添加的那些数据会被清空!只是临时添加,需要重新添加否则报错

2:必须要先添加模块所在路径才能 import 导入 目标模块,否则报错!!

image-20211012184533216

关于注意事项1的截图

image-20211012184548407

import的reload加载问题【重点】

为什么要在一段程序中重新加载模块

答:一段程序用到某模块运行时,其他人修改了这个模块的代码,但是运行的这段代码用的还是没修改之前的模块,这样就会造成损失,所以需要重新加载模块

注意事项:import 有防止模块重复功能,就是导入两个相同的模块,后面导入的那个一样的模块就不起作用了!

问题演示:

image-20211012184600024

使用 reload 方法重新加载模块

关键字:reload

语法:

1
2
from imp import reload
reload(待加载的模块名)

代码演示:

image-20211012184615552

from…import * 的私有化问题【重点】

什么是模块内变量私有化?

答:只允许模块内的变量在模块内运行时被调用打印,在别的程序内无法调用此变量

怎么实现模块内变量的私有化?

关键词:_变量名

语法:

1
2
from 模块名 import *
print(_变量名)

注意:

1:上述语法执行就会报错,因为用 from 模块名 import * 导入模块时,被下划线处理的变量是无法被导入的因此报错

2:在模块内利用下划线_ 处理的变量名,只有在 from 模块名 import * 时才能实现变量私有化,其他的任何导入方法都可以进行导入该变量!

图示:

模块内代码

image-20211012184711976

导入模块代码

image-20211012184720347

import和from…import的区别【重点】

目标:掌握 import 与 from …. import …. 两种导入模块方式的区别

import 与 from …. import …. 两种导入模块方式的区别

import导入模块:直接引用模块里面的所有内容,导入模块后对该模块内的函数、变量做出更改,那么原始模块内的数据也随之发生改变

from …. import ….导入模块:复制导入模块的所有变量、函数以及类并且拷贝到当前py文件内,不是直接引用模块内的方法等,这样对模块内的变量等进行修改后,原始模块内的数据将不发生变化!

注意事项:在掌握两种导入模块的区别之后,当遇到多个文件共享一个模块内的变量时(一个文件更改模块内容,其他文件可一接收到更改后的内容),那我们就要用到第一种导入模块的方式哦(import)

图示:

image-20211012184743276

代码:

girl模块内的代码

image-20211012184751624

可变参数的拆包问题【重点】

可变参数 *args 与 **kwargs 分别接受什么形式的数据?

*args:将接收的数据存储在元组内

接收数据形式:a ,b,c,d,e 数据之间逗号分割

**kwargs:将接受的数据存储到字典内
接受数据形式:a = 10,b = 20 赋值的方式

图示:

image-20211012184810727

如何将数据拆包并传递给其他函数

首先分析出现下面问题的原因

image-20211012184824680

问题修正

加上*** 可将 元组和字典拆包

image-20211012184831694

单继承中的super【重点】

类中的 super()方法的作用

答:调用父类中的方法
语法:super(). 父类方法 例如 super.()init(参数1,参数2…..) 调用父类的初始化方法 init(参数1,参数2…..)
注意事项:super调用父类的方法是按照 mro 顺序来调用的,因此多继承中不一定调用的就是父类方法!!

图示:

什么是__mro__序列

功能:查看目标类的父类以及祖父类等等一直向上,直到 object

语法:目标类.mro

注意事项:super调用父类的方法是按照 mro 顺序来调用的,因此多继承中不一定调用的就是父类方法!!

代码:

image-20211012184855505

单继承类中的 super 调用父类方法是遵循__mro__序列调用的

代码截图:

image-20211012184915904

结果截图:

image-20211012184922866

多继承和MRO顺序1【重点】

注意事项:super调用父类的方法是按照 mro 顺序来调用的,因此多继承中不一定调用的就是父类方法!!

目标:
1:掌握子类继承父类时调用父类方法的两种形式以及区别

2:掌握什么是多继承中的菱形继承(钻石继承)

2:掌握多继承中的mro顺序作用

子类继承父类时调用父类方法的两种形式以及区别

方法一:父类名.方法名(self,参数1,参数2……..) 例如 parent . init(self , name , age , gender)

方法二:super(). 方法名(参数1,参数2…..) 例如 super().__init__(name,age,gender)

两种方法的区别:第一种方法继承时要传递参数 self 第二种方法不需要传递 self !!

图示:

父类名.方法名(self,参数1,参数2……..)

image-20211012184943566

super(). 方法名(参数1,参数2…..)

image-20211012184958749

什么是多继承中的菱形继承(钻石继承)

图示:

image-20211012185007087

注意事项:

1:出现菱形继承时,如果操作不当(利用父类名调用父类方法),可能会出现祖父类的某方法调用多次(只想调用一次),这是我们必须要用super()继承父类方法来解决这一问题!!!

2:因此在多继承中应该尽量避免使用父类名.父类方法 这种形式调用父类的方法,会造成有的父类方法调用两次,使用super调用了完美解决

多继承中的mro顺序作用

使用语法:

1:类名.mro()

2:类名.mro

image-20211012185026156

注意事项:

1:多继承中利用 super 调用父类的方法,不一定是调用父类的方法,而是按照多继承中的 mro 顺序来调用的

2:如果子类利用super调用父类方法,父类中没有super方法 就不会按照 mro 顺序调用方法,因此要想按照 mro 顺序调用方法,必须要求所有参与继承的家族类中都要有 super方法!

注意事项:super调用父类的方法是按照 mro 顺序来调用的,因此多继承中不一定调用的就是父类方法!!

property装饰的基本使用【重点】

property装饰类中的函数的作用!

功能:在类中被 property 装饰后的函数,调用这个函数可像调用类中的属性一样使用(不用加括号了)!

语法:

1
2
3
@property
def functionself
…….

代码演示:

image-20211012185104567

在类中使用 property 装饰的注意事项

1:装饰的类函数中必须只有一个参数self,不允许有其他的参数!

property装饰的其他使用方法【重点】

property 装饰函数的 @xxxxx.setter 形式的功能!

功能:被 @xxxxx.setter 装饰的类里面的函数可以传递参数进去

语法:

1
2
3
@price.setter
def price()
……..

注意事项:

1:@xxxxx.setter 中的 xxxxx 是被装饰的函数名!

2:被@xxxxx.setter 装饰后的函数 通过实例对象.装饰函数名 = 参数 即可向被装饰后的函数传递参数!

3:@xxxxx.setter 这种装饰函数必须要在 property 装饰函数的基础上才能使用,也就是说类里面必须有 property装饰方法,才能使用 @xxxxx.setter ,并且这两种方法装饰的函数名一样!

代码演示:

image-20211012185131386

property 装饰函数的 @xxxxx.deleter 形式的功能!

语法:

1
2
3
@price.deleter
def price()
……..

代码体验:

image-20211012185142289

prepery作为类属性的值传入【重点】

类属性与实例属性的区别

定义区别:实例属性是在__init__方法里面定义的属性,而类属性是在类里面并且所有方法外面定义的属性

调用区别:实例属性只能用类创建的实例调用,类属性可以用类名调用也可以用类创建的实例调用

图示:

image-20211012185202109

property作为类属性的值传入其中四个参数作用及其使用方法!

语法:类属性变量名 = property(参数1,参数2,参数3,参数4)

其中参数1到参数3都是函数名,参数4是字符串类型的值!

使用方法:

1:当写下 类对象 . 类属性变量名 会自动调用名为参数1的函数

2:当写下 类对象 . 类属性变量名 = 500 会自动调用名为参数2的函数(这个函数有参数 传递实参为500)

3:当写下 del 类对象 . 类属性变量名 会自动调用名为参数3的函数

4:当写下 类名.类属性变量名._ doc _ 可打印参数4的值

注意事项:想打印参数4的值,要注意书写的不是类对象而是类名

代码演示:

image-20211012185218659

魔法属性和魔法方法【重点】

类的魔法属性 _ doc _的功能

功能:查看类的说明(注释)或者类里面方法的注释

语法:

1:类名.doc 或 类对象.doc 查看类的注释

2:类名.方法名.doc 或 类对象.方法名.doc 查看类里面方法的注释

代码演示:

image-20211012185237938

类的魔法属性 module 与 __class__的功能

__module__功能:查看当前类所在的模块!

语法:类名.module 或 类对象.module

__class__功能:查看当前对象所属的类!

语法:类对象.classes

代码:

image-20211012185248902

类的魔法方法 init( ) 与 del( ) 的功能

init( )功能:初始化魔法方法,在类创建对象时自动调用的方法!注意它不是构造方法,构造方法是__new__( ) 与 init( )的统称

del( ) 功能:删除方法,当删除类创建的对象时自动调用的方法!

代码:

image-20211012185258083

魔术属性 dict 的功能及其使用方法

功能:查看类对象的实例属性并将属性以键值对的形式存放在字典内或查看类的所有类属性(实例属性除外)和类方法存放在字典内

语法:

1:类对象 . dict
2:类名 . dict

代码:

image-20211012185314019

魔法方法 call( ) 与 str( ) 功能及其使用方法

call( )功能:当实例化对象加上括号时,就会调用魔法方法__call__( )

语法:实例对象()

str( ) 功能:当打印实例化对象时,就会调用__str__( ) 魔法方法,注意__str__方法内必须要有返回值,且返回值必须是字符串类型!

语法:print(实例对象)

代码演示:

image-20211012185335037

魔法方法 getitem( key ) 、 setitem( key,value )、delitem( key )的调用方法

getitem( key )调用方法:实例对象[key] 就会调用此方法

setitem( key,value )调用方法:实例对象[key] = value 就会调用此方法

delitem( key )调用方法:del 实例对象[key] 就会调用此方法

代码演示:

image-20211012185346280

with管理上下文方式【重点】

利用 with 操作文件的优点

答:与单纯的 open 打开文件相比,当 open 打开文件出现错误时,因为资源已经分配,所以对这个文件资源进行关闭操作就会失败,with 方式操作文件可有效解决这一问题!不会出现文件关闭失败的情况!

with 操作文件的步骤!

第一步:执行上下文管理类里面的上文方法即 __enter__()并且返回一个对象,也就是 as 后面的那个变量(实质是打开文件返回的对象)!

第二步:利用返回的对象对文件进行读写等操作!

第三步:执行上下文管理类里面的下文方法即 exit( ) 即关闭文件!

注意事项:

1:执行 __enter__()上文方法返回的对象也就是 as 后面的 file ,file的实质为 file = open(“文件名”,“打开方式”)的打开文件操作的语句,而非是 open类

2:下面的注释中有一处错误就是 with open(“text.txt”,“r”) 的 open 不是一个类,而是一个上下文管理函数!!

代码:

image-20211012185403180

自己构建一个上下文管理器类实现读取指定文件内容

什么是上下文管理器?

答:即支持 with 操作的类或者函数!

上下文管理器类包含的方法:

1:初始化方法__init__( ) 用来接收参数【文件名、打开方式】

2:上文方法__enter__( ) 用来打开文件并且返回这个对象

3:下文方法__exit__( ) 用来关闭打开的文件!

注意事项:类里面如果有多个方法想共用一个变量,那么这个变量要变成实例属性的方式才行,也就是加上self

代码:

image-20211012185419418

利用装饰器装饰函数的方法实现 with 上下文管理操作文件(读取文件内所有数据)!

实现关键字:

yield:函数内 yield上方为上文,下方为下文,调用函数时,第一次调用执行到 yield 处,第二次执行从 yield 继续执行!
yield有返回数据以及退出函数的功能

contextlib 库里面的装饰器 contextmanager :利用 contextmanager 装饰器装饰写好的函数即可实现 with 上下文管理操作文件

实现步骤:

第一步:定义一个函数,传递两个参数即文件名以及文件打开方式

第二步:在函数内部打开指定文件,并用 yield 返回打开文件的对象,yield上方的也就是上文

第三步:在 yield 下方对打开的文件对象进行关闭!也就是上下文管理的下文

第四步:导入 contextlib 模块里面的装饰器 contextmanager

第五步:利用 @contextmanager 装饰写好的函数

第六步:利用

1
2
3
with 函数名(“文件名”,“打开方式”) as file :
result = file.read()
print(result)

读取指定文件的所有数据

代码体验:

image-20211012185438098

未完待续……