Python高级基础

Python高级基础

1.文件

1.1文件操作步骤

  • 打开文件

  • 读写等操作

  • 关闭文件

1.1.1文件操作的函数/方法

序号 函数/方法 说明
01 open 打开文件,并且返回文件操作对象
02 read 将文件内容读取到内存
03 write 将指定内容写入文件
04 close 关闭文件
  • open 函数负责打开文件,并且返回文件对象

  • read/write/close 三个方法都需要通过 文件对象 来调用

  • open 函数的第一个参数是要打开的文件名(文件名区分大小写)

    • 如果文件 存在,返回 文件操作对象

    • 如果文件 不存在,会 抛出异常

  • read 方法可以一次性 读入返回 文件的 所有内容

  • close 方法负责 关闭文件

1)打开/写入文件

在Python中,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件,语法如下:

 open(name, mode)

name:是要打开目标文件名的字符串(可以包含文件所在的具体路径)

mode:设置打开文件的模式(访问模式):只读、写入、追加等

访问方式 说明
r 只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常
w 只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a 追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入
r+ 读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常
w+ 读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a+ 读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入

提示

  • 频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以 只读只写 的方式来操作文件

打开文件并进行写入示例

 # 打开文件
 f = open("README", "w")
 ​
 f.write("hello python!\n")
 f.write("今天天气真好")
 ​
 # 关闭文件
 f.close()

2)读取文件

1. read()

 文件对象.read(num)

num表示要从文件中读取的数据的长度(单位都是字节),如果没有传入num,那么就表示读取文件的所有数据

一次性读取文件内容

 # 1. 打开 - 文件名需要注意大小写
 file = open("README")
 ​
 # 2. 读取
 text = file.read()
 print(text)
 ​
 # 3. 关闭
 file.close()

注意read 方法执行后,会把 文件指针 移动到 文件的末尾

文件指针

  • 文件指针 标记 从哪个位置开始读取数据

  • 第一次打开 文件时,通常 文件指针会指向文件的开始位置

  • 当执行了 read 方法后,文件指针 会移动到 读取内容的末尾

    • 默认情况下会移动到 文件末尾

2. readlines()

readlines可以按照行的方式把整个文件中的内容按行进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素

 fp = open("E:\student.txt", "r")
 result = fp.readlines()
 print(result)  # ['aaa\n', 'bbb\n', 'ccc\n', 'ddd']
 fp.close()

3. readline()

  • readline 方法可以一次读取一行内容

  • 方法执行后,会把 文件指针 移动到下一行,准备再次读取,适用于读取大文件

读取大文件的正确姿势

 # 打开文件
 file = open("README")
 ​
 while True:
     # 读取一行内容
     text = file.readline()
 ​
     # 判断是否读到内容
     if not text:
         break
 ​
     # 每读取一行的末尾已经有了一个 `\n`
     print(text, end="")
 ​
 # 关闭文件
 file.close()

1.1.2 r+ 和 w+ 和 a+ 区别

 """
 1. r+ 和 w+ a+区别
 2. 文件指针对数据读取的影响
 3. test.txt已存在并且有数据,test1.txt不存在
 """
 # r+: 文件不存在则报错,文件指针在开头,能够读出数据
 # f = open('test1.txt', 'r+')
 # f = open('test.txt', 'r+')
 ​
 # w+:文件不存在会新建文件,文件指针在开头,读数据时会用新内容覆盖原内容
 # f = open('test1.txt', 'w+')
 # f = open('test.txt', 'w+')
 ​
 # a+:文件不存在会新建文件,文件指针在末尾,不能够读出数据
 f = open('test1.txt', 'a+')
 f = open('test.txt', 'a+')
 con = f.read()
 print(con)
 ​
 f.close()

1.1.3 seek()

作用:用来移动文件指针

语法如下:

 文件对象.seek(偏移量, 起始位置)

起始位置:

  • 0:文件开头

  • 1:当前位置

  • 2:文件结尾

# r 改变文件指针位置:改变读取数据开始位置或把文件指针放在末尾(无法读取数据)
fp = open('E:/student.txt', 'r')

# 改变文件指针,读取改变后的数据
fp.seek(6, 0)
# 文件指针放在末尾(无法读取数据)
# fp.seek(0, 2)
con = fp.read()
print(con)

fp.close()

1.2 文件备份

需求:用户输入当前目录下任意文件名,程序完成对该文件的备份功能(备份文件名为xx[备份]后缀,例如:test[备份].txt)

1.2.1步骤

  1. 接收用户输入的文件名

  2. 规划备份文件名

  3. 备份文件写入数据

1.2.2代码实现

# 1.接收用户输入目标文件
old_name = input('请输入你要备份的文件名:')

# 2.规划备份文件的名字
# 2.1提取目标文件后缀
index = old_name.rfind('.')
# 2.2有效文件才备份
if index > 0:
    postfix = old_name[index:]
else:
    print("输入文件名无效!")
# 2.3组织新文件名:旧文件名 + [备份] + 后缀
new_name = old_name[:index] + '[备份]' + postfix
print(new_name)

# 3.备份文件写入数据(数据和原文件一样)
# 3.1打开文件
old_fp = open(old_name, 'rb')
new_fp = open(new_name, 'wb')

# 3.2将原文件数据写入备份文件
while True:
    con = old_fp.read(1024)
    if len(con) == 0:
        break
    new_fp.write(con)

# 3.3关闭文件
old_fp.close()
new_fp.close()

1.3文件和文件夹的操作

在Python中文件和文件夹的操作要借助os模块里面的相关功能,具体步骤如下:

  1. 导入os模块

    import os
  2. 使用os模块相关功能

os.函数名()

1.3.1文件重命名

os.rename(目标文件名,新文件名)

1.3.2删除文件

os.remove(目标文件名)
# 导入模块os
import os

# 1.rename():重命名
os.rename('test.txt', 'lyc.txt')

# 2.remove():删除文件
os.remove('test[备份].txt')

1.3.3创建文件夹

os.mkdir(文件夹名字)

1.3.4删除文件夹

os.rmdir(文件夹名字)

1.3.5获取当前目录

os.getcwd()

1.3.6改变默认目录

os.chdir(目录)

1.3.7获取目录列表

os.listdir(目录)
# 导入模块os
import os

# 1.mkdir():创建文件夹
# os.mkdir('lyc')

# 2.rmdir():删除文件夹
# os.rmdir('lyc')

# 3.getcwd():获取当前目录
path = os.getcwd()
print(path)

# 4.chdir():改变默认目录路径
# 需求:在lyc文件夹里创建文件夹aa
# os.mkdir('lyc')
# os.chdir('lyc')
# os.mkdir('aa')

# 5.listdir():获取目录列表
print(os.listdir('lyc'))

# 6.rename():重命名文件夹
os.rename('lyc', 'bb')

1.3.8应用案例

需求:批量修改文件名,既可添加指定字符串,又能删除指定字符串

  • 步骤

    1. 设置添加删除字符串的标识

    2. 获取指定目录的所有文件

    3. 将原有文件名添加/删除指定字符串,构造新名字

    4. os.rename()重命名

  • 代码

# 需求1:把code文件夹所有文件重命名 Python_xxxx
import os

# 设置重命名标识:如果flag取值为1则添加指定字符,flag取值为2则删除指定字符
flag = 1
# 获取指定目录
dir_name = './'

# 获取指定目录的文件列表
file_list = os.listdir(dir_name)

# 遍历文件列表内的文件
for name in file_list:
    # 添加指定字符
    if flag == 1:
        new_name = 'Python_' + name
    # 删除指定字符
    elif flag == 2:
        num = len('Python_')
        new_name = name[num:]
    # 打印新文件名,测试程序正确性
    print(new_name)
    # 重命名
    os.rename(dir_name+name,dir_name+new_name)

2.面向对象

面向对象就是将编程当成一个是一个事物,对外界来说,事物是直接食用的,不用去管他内部的情况。而编程就是设置事物能够做什么事

2.1类和对象

在面向对象编程过程中,有两个重要组成部分:类和对象

类和对象关系:用类去创建一个对象

2.1.1类

类是一系列具有相同特征和行为的事物的统称,是一个抽象概念,不是真实存在的事物

  • 特征即是属性

  • 行为即是方法

2.1.2对象

对象是创建出来的真实存在的事物

2.2面向对象实现方法

2.2.1定义类

Python2中类分为:经典类和新式类

  • 语法

class 类名():
    代码
    .......

注意:类名要满足标识符的命名规则,同时遵循大驼峰命名习惯

2.2.2创建对象

对象又名实例

  • 语法

对象名 = 类名()
  • 体验

# 需求:洗衣机 功能:洗衣服
# 1.定义洗衣机类
class Washer():
    def wash(self):
        print("洗衣服")

# 2.创建对象
haier = Washer()
# 实例方法  对象名.wash()
haier.wash()

2.2.3self

self指的是调用该函数的对象

# 需求:洗衣机 功能:洗衣服
# 1.定义洗衣机类
class Washer():
    def wash(self):
        print("我会洗衣服")
        # <__main__.Washer object at 0x000001EAE7699A58>
        print(self)

# 2.创建对象
haier = Washer()
# <__main__.Washer object at 0x000001EAE7699A58>
print(haier)
haier.wash()

2.3添加和获取对象属性

属性即是特征,比如:洗衣机的宽度、高度、重量...

对象属性既可以是在类外面添加和获取,也能在类里面添加和获取

2.3..1类外面添加对象属性

  • 语法

对象名.属性名 = 值
  • 体验

haier.width = 500
haier.height = 800

2.3.2类外面获取对象属性

  • 语法

对象名.属性名
  • 体验

print(f'haier洗衣机的宽度是{haier.width}')
print(f'haier洗衣机的高度是{haier.height}')

2.4类里面获取对象属性

  • 语法

self.属性名
  • 体验

# 1.定义洗衣机类
class Washer():
    def print_info(self):
        # 类里面获取实例属性
        print(f'haier洗衣机的宽度是{self.width}')
        print(f'haier洗衣机的高度是{self.height}')

# 2.创建对象
haier = Washer()

haier.width = 400
haier.height = 500

haier.print_info()

2.5魔法方法

在Python中,__xx__()的函数叫做魔法方法,指的是具有特殊功能的函数

2.5.1__init__()

2.5.1.1体验__init__()

__init__方法的作用:初始化对象。

class Washer():
    # 定义__init__,添加实例属性
    def __init__(self):
        # 添加实例属性
        self.width = 500
        self.height = 800
        self.color = 'red'

    def print_info(self):
        # 类里面调用实例属性
        print(f'洗衣机的宽度是{self.width},高度是{self.height}')

haier = Washer()
# 洗衣机的宽度是500,高度是800
haier.print_info()

注意:

  • __init__()方法,在创建一个对象时默认被调用,不需要手动调用

  • __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去

2.5.1.2带参数的__init()

思考:一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢?

答:传参数

class Washer():
    # 定义__init__,添加实例属性
    def __init__(self, width, height, color):
        # 添加实例属性
        self.width = width
        self.height = height
        self.color = color

        
    def print_info(self):
        # 类里面调用实例属性
        print(f'洗衣机的宽度是{self.width},高度是{self.height},颜色是{self.color}')

        
haier1 = Washer(100, 300, 'red')
haier1.print_info()

haier2 = Washer(400, 500, 'white')
haier2.print_info()

2.5.2__str__()

当使用print输出对象的时候,默认打印对象的内存地址。如果定义了__str__方法,那么就会打印从这个方法中return的数据

class Washer():
    # 定义__init__,添加实例属性
    def __init__(self, width, height, color):
        # 添加实例属性
        self.width = width
        self.height = height
        self.color = color
	# 解释说明信息
    def __str__(self):
        return '洗衣机宽度是:' + str(self.width) + ',洗衣机宽度:' + str(self.height) + ',洗衣机颜色是:' + self.color


haier1 = Washer(100, 300, 'red')
print(haier1)

2.5.3__del__()

当删除对象时,python解释器也会默认调用__del__()方法

class Washer():
    # 定义__init__,添加实例属性
    def __init__(self, width, height, color):
        # 添加实例属性
        self.width = width
        self.height = height
        self.color = color

    def __del__(self):
        print(f'{self}对象已经被删除')

# <__main__.Washer object at 0x000002C8E3429080>对象已经被删除
haier1 = Washer(100, 300, 'red')

2.6综合应用

2.6.1烤地瓜

2.6.1.1需求:

需求:

  1. 被烤的时间和对应的地瓜状态:

    0-3分钟:生的

    3-5分钟:半生不熟

    5-8分钟:熟的

    超过8分钟:烤糊了

  2. 添加的调料

    用户可以按自己的意愿添加调料

2.6.2步骤分析

需求涉及一个事物: 地瓜,故案例涉及一个类:地瓜类

2.6.2.1定义类

  • 地瓜的属性

    • 被烤的时间

    • 地瓜的状态

    • 添加的佐料

  • 地瓜的方法

    • 被烤

      • 用户根据意愿设定每次烤地瓜的时间

      • 判断地瓜被烤的总时间是在哪个区间,修改地瓜状态

    • 添加佐料

      • 用户根据意愿设定添加的佐料

      • 将用户添加的佐料存储

  • 显示对象信息

2.6.2.2代码实现

class SweetPotato():

    def __init__(self):
        # 被烤的时间
        self.cook_time = 0
        # 烤的状态
        self.cook_state = '生的'
        # 佐料列表
        self.condiments = []

    def cook(self, time):
        """烤地瓜方法"""
        self.cook_time += time
        if 0 <= self.cook_time < 3:
            self.cook_state = '生的'
        elif 3 <= self.cook_time < 5:
            self.cook_state = '半生不熟的'
        elif 5 <= self.cook_time < 8:
            self.cook_state = '熟了的'
        elif 8 <= self.cook_time:
            self.cook_state = '糊了的'

    def __str__(self):
        return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_state},添加的调料有{self.condiments}'

    def add_condiments(self, condiment):
        """添加佐料"""
        self.condiments.append(condiment)


digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
digua1.add_condiments('辣椒面')
print(digua1)

digua1.cook(2)
digua1.add_condiments('食盐')
print(digua1)

digua1.cook(2)
digua1.add_condiments('孜然粉')
print(digua1)

2.7继承

Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:

# 父类A
class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


# 子类B
class B(A):
    # 空语句,保持程序的完整性
    pass


result = B()
result.info_print() # 1

在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫派生类

2.7.1单继承

所谓单继承就是一个类继承一个父类

# 1.师父类
class Master(object):
    def __init__(self):
        self.koufu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.koufu}制作煎饼果子')


# 2.徒弟类继承师父类Master
class Prentice(Master):
    pass

# 3.创建对象daqiu
daqiu = Prentice()
# 4.对象访问实例属性
print(daqiu.koufu)
daqiu.make_cake()

2.7.2多继承

所谓多继承就是一个类同时继承多个父类

# 1.师父类
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


# 2.学校类
class School(object):
    def __init(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


# 2.徒弟类
class Prentice(Master, School):
    pass

# 3.创建对象daqiu
daqiu = Prentice()
# 4.对象访问实例属性
# [古法煎饼果子配方]
print(daqiu.kongfu)
# 运用[古法煎饼果子配方]制作煎饼果子
daqiu.make_cake()

注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法

2.7.3子类重写父类同名方法和属性

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
# 类名.__mro__得到该类的继承关系
print(Prentice.__mro__)

注意:当子类重写父类的同名属性和方法时,子类创建对象调用属性和方法时,调用到的是子类中的同名属性和方法

2.7.4子类调用父类的同名方法和属性

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    def make_master_cake(self):
        # 如要调用父类的同名方法和属性,必须先调用__init()方法
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


daqiu = Prentice()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
daqiu.make_cake()

2.7.5多层继承

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    def make_master_cake(self):
        # 如要调用父类的同名方法和属性,必须先调用__init()方法
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)


class Tusun(Prentice):
    pass

daqiu = Tusun()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()

2.7.6 super()调用父类方法

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(Master):
    def __init__(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')
        # 2.1super()带参数写法
        # super(School, self).__init__()
        # super(School, self).make_cake()
        # 2.2super()不带参数写法
        super().__init__()
        super().make_cake()

class Prentice(School):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    def make_cake(self):
        # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 需求:一次性调用父类School,Master的方法
    def make_old_cake(self):
        # 方法一: 如果定义的类名修改,这里也要修改,麻烦,代码量大,冗余
        # Master.__init__(self)
        # Master.make_cake(self)
        # School.__init__(self)
        # School.make_cake(self)

        # 方法二:super()
        # 方法2.1 super(当前类名,self).函数()
        # super(Prentice, self).__init__()
        # super(Prentice, self).make_cake()
        # 2.2super()不带参数写法
        super().__init__()
        super().make_cake()
        
        
daqiu = Prentice()
daqiu.make_old_cake()

2.8私有权限

2.8.1定义私有属性和方法

在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。

设置私有权限的方法:在属性名和方法名前面加上两个下划线__

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
        # 私有属性
        self.__money = 2000

    # 定义私有方法
    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Tusun(Prentice):
    pass


# 对象不能访问私有属性和方法
# daqiu = Prentice()
# print(daqiu.__money)
# daqiu.info_print()

# 子类无法继承父类的私有属性和私有方法
# xiaoqiu = Tusun()
# print(xiaoqiu.__money)
# xiaoqiu.__info_print()

2.8.2获取或修改私有属性值

在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class School(object):
    def __init__(self):
        self.kongfu = '[蜜汁煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'
        self.__money = 2000
	# 设置私有属性值
    def set_money(self, money):
        self.__money = money
        
	# 获取私有属性值
    def get_money(self):
        return self.__money

    # 定义私有方法
    def __info_print(self):
        print(self.kongfu)
        print(self.__money)

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


class Tusun(Prentice):
    pass


xiaoqiu = Tusun()
xiaoqiu.set_money(200000000)
print(xiaoqiu.get_money())

2.9面向对象三大特性

  • 封装

    • 将属性和方法书写到类的里面的操作即为封装

    • 封装可以为属性和方法添加私有权限

  • 继承

    • 子类默认继承父类的所有属性和方法

    • 子类可以重写父类的属性和方法

  • 多态

    • 传入不同的对象,产生不同的结果

2.9.1多态

多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

  • 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果

  • 好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化

  • 实现步骤:

    • 定义父类,并提供公共方法

    • 定义子类,并重写父类方法

    • 传递子类对象给调用者,可以看到不同子类执行效果不同

2.9.2体验多态

class Dog(object):
    def work(self):
        # 父类提供统一方法,哪怕是空方法
        pass


class ArmyDog(Dog):
    # 继承Dog类
    def work(self):  # 子类重写父类同名方法
        print("追击敌人...")


class DrugDog(Dog):
    def work(self):
        print("追查毒品...")


class Person(object):
    def work_with_dog(self, dog):  # 传入不同的对象,执行不同的代码,即不同的work函数
        dog.work()


ad = ArmyDog()
dd = DrugDog()

person = Person()
person.work_with_dog(ad)
person.work_with_dog(dd)

2.9.3类属性和实例属性

2.9.3.1设置和访问类属性

  • 类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有

  • 类属性可以使用类对象或实例对象访问

class Dog(object):
    tooth = 10


huahua = Dog()
xiaohei = Dog()

print(Dog.tooth)  # 10
print(huahua.tooth)  # 10
print(xiaohei.tooth)  # 10

2.9.3.1.2修改类属性

类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建一个实例属性

class Dog(object):
    tooth = 10


huahua = Dog()
xiaohei = Dog()

# 修改类属性
Dog.tooth = 12
print(Dog.tooth)  # 12
print(huahua.tooth)  # 12
print(xiaohei.tooth)  # 12

# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
huahua.tooth = 20
print(Dog.tooth)  # 12
print(huahua.tooth)  # 20
print(xiaohei.tooth)  # 12

2.9.4类方法和静态方法

2.9.4.1类方法

2.9.4.1.1类方法特点

  • 需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数

2.9.4.1.2类方法的使用场景

  • 当方法中需要使用类对象(如访问私有属性等)时,定义类方法

  • 类方法一般和类属性配合使用

class Dog(object):
    __tooth = 10

    @classmethod
    def get_tooth(cls):
        return cls.__tooth


wangcai = Dog()
result = wangcai.get_tooth()
print(result)  # 10

2.9.4.2静态方法

2.9.4.2.1静态方法特点

  • 需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)

  • 静态方法也能够通过实例对象和类对象去访问

2.9.4.2.2静态方法使用场景

  • 当方法中既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性、类方法、创建实例等)时,定义静态方法

  • 取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗

class Dog(object):
    @staticmethod
    def info_print():
        print("这是一个狗类,用于创建狗实例...")


wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()

3.异常

3.1了解异常

当检测到一个错误时,解释器无法继续执行时,反而出现了一些错误提示,这就是所谓的“异常”

例如:以r方式打开一个不存在的文件

open('test.txt', 'r')
D:\software\Python\Python37\python.exe E:/PycharmProjects/Python_Base/Python_Test_1/面向对象.py
Traceback (most recent call last):
  File "E:/PycharmProjects/Python_Base/Python_Test_1/面向对象.py", line 1, in <module>
    open('test.txt', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'

3.2异常的写法

3.2.1语法

try:
    可能发生错误的代码
except:
    如果出现异常执行的代码

3.2.2体验

需求:尝试以r模式打开文件,如果文件不存在,则以w方式打开

try:
    f = open('test.txt', 'r')
except:
    f = open('test.txt', 'w')
f.close()

3.3捕获指定异常

3.3.1语法

try:
    可能发生错误的代码
except 异常代码:
    如果捕获到该异常类型执行的代码

3.3.2体验

try:
    print(num)
except NameError:
    print("有错误")

注意:

1.如果尝试执行的代码的异常类型和要捕获的异常类型不一致时,则无法捕获异常

2.一般try下只放一行尝试执行的代码

3.4捕获多个指定异常

当捕获多个指定异常时,可以把要捕获的异常类型的名字,放到except后,并使用元组的方式进行书写

try:
    print(1/0)
except (NameError, ZeroDivisionError):
    print("有错误")

3.5捕获指定异常描述信息

try:
    print(1/0)
except (NameError, ZeroDivisionError) as result:
    print(result)

3.6捕获所有异常

Exception是所有程序异常类的父类

try:
    print(num)
except Exception as result:
    print(result)

3.7异常的else

else表示的是如果没有异常要执行的代码

try:
    print(1)
except Exception as result:
    print(result)
else:
    print("没有异常时,执行的代码")

3.8异常的finally

finally表示的是无论是否异常都要执行的代码,例如关闭文件

try:
    f = open('test1.txt', 'r')
except:
    f = open('test1.txt', 'w')
else:
    print("没有异常,真开心")
finally:
    f.close()

3.9异常的传递

体验异常传递

需求:

  1. 尝试只读方式打开test.txt文件,如果文件存在则读取文件内容,文件不存在则提示用户即可

  2. 读取内容要求:尝试循环读取内容,读取过程中如果检测到用户意外终止程序,则except捕获异常并提示用户

import time
try:
    f = open('test.txt')
    try:
        while True:
            content = f.readline()
            if len(content) == 0:
                break
            time.sleep(2)
            print(content)
    except:
        # 如果在读取文件的过程中,产生了异常,那么就会捕获到
        # 比如按下了ctrl+c
        print("意外终止读取数据")
    finally:
        f.close()
        print("关闭文件")
except:
    print("文件不存在")

3.10自定义异常

在Python中,抛出自定义异常的语法为raise 异常对象

需求:密码长度不足,则报异常(用户输入密码,如果输入的长度不足3位,则报错,即抛出自定义异常,并捕获该异常)

# 自定义异常类,继承Exception
class ShortInputError(Exception):
    def __init__(self, length, min_len):
        self.length = length
        self.min_len = min_len

    # 设置抛出异常的描述信息
    def __str__(self):
        return f'你输入的长度是{self.length},不能少于{self.min_len}个字符'


def main():
    try:
        con = input("请输入密码:")
        if len(con) < 3:
            raise ShortInputError(len(con), 3)
    except Exception as result:
        print(result)
    else:
        print("密码已经输入完成")


main()

4.模块和包

4.1模块

Python模块(Module),是一个Python文件,以.py结尾,包含了Python对象定义和Python语句

模块能定义函数,类和变量,模块里也能包含可执行的代码

4.1.1导入模块的方式

  • import 模块名

  • from 模块名 import 功能名

  • from 模块名 import *

  • import 模块名 as 别名

  • from 模块名 import 功能名 as 别名

4.1.1.1导入方式详解

1.import

  • 语法

# 1.导入模块
import 模块名
import 模块名1,模块名2... #  不推荐

# 2.调用功能
模块名.功能名()
  • 体验

import math
print(math.sqrt(9))

2.from...import...

  • 语法

# 1.导入模块
from 模块名 import 功能1, 功能2, 功能3...
# 2.调用功能
功能名()
  • 体验

from math import sqrt
print(sqrt(9))

3.from...import *

  • 语法

# 1.导入模块
from 模块名 import *
# 2.调用功能
功能名()
  • 体验

from math import *
print(sqrt(9))

4.as定义别名

  • 语法

# 模块定义别名
import 模块名 as 别名

# 功能定义别名
from 模块名 import 功能 as 别名
  • 体验

# 模块别名
import time as tt

tt.sleep(2)
print("hello")

# 功能别名
from time import sleep as sl
sl(2)
print('hello')

4.2制作模块

在Python中,每个Python中都可以作为一个模块,模块的名字就是文件的名字。也就是说自定义模块名必须要符合标识符命名规则

4.2.1定义模块

新建一个Python文件,命名为my_module1.py,并定义testA函数

def testA(a, b):
    print(a + b)

4.2.2测试模块

在实际开发中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如,在my_module1.py文件中添加测试代码

def testA(a, b):
    print(a + b)

# 测试信息
testA(1, 1)

此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行testA函数的调用

解决办法如下:

def testA(a, b):
    print(a + b)


# 只在当前文件调用该函数,其他导入的文件内不符合该条件,则不执行testA函数调用
# __name__是系统变量,是模块的标识符,值是:如果是自身模块,值是__main__,否则是当前模块的名字
if __name__ == '__main__':
    testA(1, 1)

4.2.3调用模块

import my_module1

my_module1.testA(2, 2)

4.3模块定位顺序

当导入一个模块,Python解析器对模块位置的搜索顺序是:

  1. 当前目录

  2. 如果不在当前目录,Python则搜索在shell变量PYTHONPATH的每个目录

  3. 如果都找不到,Python会查看默认目录。UNIX下,默认路径一般为/usr/local/lib/python/

模块搜素路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录

  • 注意

    • 自己的文件名不要和已有模块名重复,否则导致模块功能无法使用

    • 使用from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能

4.4__all__(all列表)

如果一个模块文件中有__all__变量,当使用from xxx import *导入时,只能导入这个列表中的元素

  • my_module1模块的代码

__all__ = ['testA']


def testA():
    print('testA')


def testB():
    print('testB')
  • 导入模块的文件代码

from my_module1 import *
testA()
testB()
testA
Traceback (most recent call last):
  File "E:/PycharmProjects/Python_Base/Python_Test_1/1.py", line 3, in <module>
    testB()
NameError: name 'testB' is not defined

4.5包

包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py文件,那么这个文件夹就称之为包

4.5.1制作包

[New]——[Python Package]——输入包名——[OK]——新建功能模块(有联系的模块)

注意:新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为

4.5.1.1快速体验

  1. 新建包mypackage

  2. 新建包内模块:my_module1和my_module2

  3. 模块代码如下

# my_module1
print(1)


def info_print1():
    print('my_module1')
# my_module2
print(2)


def info_print1():
    print('my_module2')

4.5.2导入包

4.5.2.1方法一

import 包名.模块名

包名.模块名.功能

4.5.2.2体验

import mypackage.my_module1

mypackage.my_module1.info_print1()

4.5.2.3方法二

注意:必须在__init__.py文件中添加__all__ = [],允许控制导入的模块列表

from 包名 import *
模块名.目标

4.5.2.4体验

from mypackage import *

my_module1.info_print1()

__init__.py代码

__all__ = ['my_module1']

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章