Python入门学习笔记(四)

本文是在课程课件基础上修改的学习笔记
如有侵删
课程原地址:https://www.bilibili.com/video/BV1o4411M71o
Python入门学习笔记(一)
Python入门学习笔记(二)
Python入门学习笔记(三)

二十一、文件操作

基本操作

打开

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

open(name, mode) 

name:是要打开的目标文件名的字符串(可以包含文件所在的具体路径)
mode:设置打开文件的模式(访问模式):只读、写入、追加等

打开文件模式
模式描述
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式
rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式
r+打开一个文件用于读写。文件指针将会放在文件的开头
rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头
w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件
w+打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写⼊
ab以二进制格式打开一个文件⽤于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写⼊入到已有内容之后。如果该文件不存在,创建新文件进行写入
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写

语法

对象.write('内容') 
# 1. 打开文件
f = open('test.txt', 'w')
# 2.文件写入
f.write('hello world')
# 3. 关闭文件
f.close()

注意:

  1. w 和 a 模式:如果文件不存在则创建该文件;如果文件存在, w 模式先清空再写入, a 模式直接末尾追加。
  2. r 模式:如果文件不存在则报错。

文件对象.read(num)

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

readlines()

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

f = open('test.txt')
content = f.readlines()
# ['hello world\n', 'abcdefg\n', 'aaa\n', 'bbb\n', 'ccc']
print(content)
# 关闭文件
f.close()

readline()

readline()一次读取一行内容

f = open('test.txt')
#第一行:hello world
content = f.readline()
print(f'第一行:{content}')

#第二行:abcdefg
content = f.readline()
print(f'第二行:{content}')

# 关闭文件
f.close()

seek()

作用:用来移动文件指针

语法

文件对象.seek(偏移量, 起始位置)
起始位置:
0:文件开头
1:当前位置
2:文件结尾

文件备份

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

步骤:

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

  2. 规划备份文件名

  3. 备份文件写入数据

  4. 接收用户输入目标文件名

old_name = input('请输入您要备份的文件名:') 
  1. 规划备份文件名
    2.1 提取目标文件后缀
    2.2 组织备份的文件名,xx[备份]后缀

    # 2.1 提取文件后缀点的下标
    index = old_name.rfind('.')
    # print(index) # 后缀中.的下标
    # print(old_name[:index]) # 源文件名(无后缀)
    # 2.2 组织新文件名 旧文件名 + [备份] + 后缀
    new_name = old_name[:index] + '[备份]' + old_name[index:]
    # 打印新文件名(带后缀)
      print(new_name)
    
    1. 备份文件写入数据
      3.1 打开源文件和备份文件
      3.2 将源文件数据写入备份文件
      3.3 关闭文件
# 3.1 打开文件
old_f = open(old_name, 'rb')
new_f = open(new_name, 'wb')
# 3.2 将源文件数据写入备份文件
while True:
    con = old_f.read(1024)
    if len(con) == 0:
        break
        new_f.write(con)
# 3.3 关闭文件
old_f.close()
new_f.close()

文件和文件夹的操作

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

  1. 导入os模块

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

    os.函数名()
    

    文件重命名

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

    删除文件

    os.remove(目标文件名) 
    

    创建文件夹

    os.mkdir(文件夹名字) 
    

    删除文件夹

    os.rmdir(文件夹名字) 
    

    获取当前目录

    os.getcwd() 
    

    改变默认目录

    os.chdir(目录)
    

    获取目录列表

    os.listdir(目录)
    

应用案例

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

  1. 设置添加删除字符串的的标识
  2. 获取指定目录的所有文件
  3. 将原有文件名添加/删除指定字符串,构造新名字
  4. os.rename()重命名
mport os
# 设置重命名标识:如果为1则添加指定字符,flag取值为2则删除指定字符
flag = 1
# 获取指定目录
dir_name = './'
# 获取指定目录的⽂文件列列表
file_list = os.listdir(dir_name)
# print(file_list)
# 遍历文件列表内的文件
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)

二十二、面向对象基础

面向对象理解

面向对象是一种抽象化的编程思想,很多编程语言中都有的一种思想

例如:洗衣服

思考:几种途径可以完成洗衣服?

答:

手洗和机洗
手洗:找盆 - 放水 - 加洗衣粉 - 浸泡 - 搓洗 - 拧干水 - 倒水 - 漂洗N次 - 拧干 - 晾晒
机洗:打开洗衣机 - 放衣服 - 加洗衣粉 - 按下开始按钮 - 晾晒

思考:对比两种洗衣服途径,同学们发现了什么?

答:机洗更简单

思考:机洗,只需要找到一台洗衣机,加入简单操作就可以完成洗衣服的工作,而不需要关心洗衣机内部发生了什么事情

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

类和对象

思考:洗衣机洗衣服描述过程中,洗衣机其实就是一个事物,即对象,洗衣机对象哪来的呢?
答:洗衣机是由工厂工人制作出来。
思考:工厂工人怎么制作出的洗衣机?
答:工人根据设计师设计的功能图纸制作洗衣机。
总结:图纸 → 洗衣机 → 洗衣服。
在面向对象编程过程中,有两个重要组成部分:类和对象。
类和对象的关系:用类去创建一个对象。

理解类和对象

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

  • 特征即是属性

  • 行为即是方法

    类比如是制造洗衣机时要用到的图纸,也就是说类是用来创建对象。

对象

对象是类创建出来的真实存在的事物,例如:洗衣机。

开发中,先有类,再有对象。

面向对象实现方法
定义类

语法

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

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

class Washer():
    def wash(self):
        print('我会洗衣服')

不由任意内置类型派生出的类,称之为经典类

class 类名:
    代码
    ......
创建对象

语法

对象名 = 类名()
# 创建对象
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)
# haier对象调用实例方法
haier1.wash()

注意:创建对象的过程也叫实例化对象

self

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

# 1. 定义类
class Washer():
    def wash(self):
        print('我会洗衣服')
        # <__main__.Washer object at 0x0000024BA2B34240>
print(self)
# 2. 创建对象
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)
# haier1对象调用实例方法
haier1.wash()

haier2 = Washer()
# <__main__.Washer object at 0x0000022005857EF0>
print(haier2)

注意:打印对象和self得到的结果是一致的,都是当前对象的内存中存储地址。

添加和获取对象属性

属性即是特征,比如:洗衣机的宽度、高度、重量…
对象属性既可以在类外面添加和获取,也能在类里面添加和获取

类外面添加对象属性

语法

对象名.属性名 =

体验

haier1.width = 500
haier1.height = 800

类外面获取对象属性

语法

对象名.属性名

体验

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

类里面获取对象属性

语法

self.属性名
# 定义类
class Washer():
    def print_info(self):
        # 类里面获取实例属性
        print(f'haier1洗衣机的宽度是{self.width}')
        print(f'haier1洗衣机的高度是{self.height}')
# 创建对象
haier1 = Washer()
# 添加实例属性
haier1.width = 500
haier1.height = 800
haier1.print_info()

魔法方法

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

__ init __()

作用:初始化对象

class Washer():
    # 定义初始化功能的函数
    def __init__(self):
        # 添加实例属性
        self.width = 500
        self.height = 800
	def print_info(self):
    # 类里面调用实例属性
    	print(f'洗衣机的宽度是{self.width}, 高度是{self.height}')
haier1 = Washer()
haier1.print_info()

注意:
_ init _ () 方法,在创建一个对象时默认被调用,不需要手动调用
_init _(self) 中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去

带参数的__init__()

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

答:传参数。

class Washer():
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def print_info(self):
        print(f'洗衣机的宽度是{self.width}')
        print(f'洗衣机的高度是{self.height}')
haier1 = Washer(10, 20)
haier1.print_info()
haier2 = Washer(30, 40)
haier2.print_info()
__ str __()

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

class Washer():
	def __init__(self, width, height):
		self.width = width
		self.height = height
	def __str__(self):
		return '这是海尔洗衣机的说明书'
haier1 = Washer(10, 20)
# 这是海尔洗衣机的说明书
print(haier1)
_ del _()

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

class Washer():
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def __del__(self):
        print(f'{self}对象已经被删除')
haier1 = Washer(10, 20)
# <__main__.Washer object at 0x0000026118223278>对象已经被删除
del haier1

综合应用

烤地瓜

需求:

需求主线:

  1. 被烤的时间和对应的地瓜状态:
    0-3分钟:生的
    3-5分钟:半生不熟5-8分钟:熟的
    超过8分钟:烤糊了

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

步骤分析:

  • 地瓜的属性
    被烤的时间
    地瓜的状态
    添加的调料

  • 地瓜的方法

    被烤
    用户根据意愿设定每次烤地瓜的时间
    判断地瓜被烤的总时间是在哪个区间,修改地瓜状态

    ​ 添加调料
    ​ 用户根据意愿设定添加的调料
    ​ 将用户添加的调料存储

  • 显示对象信息

class DiGua():
    def __init__(self):#定义地瓜初始化属性,后期根据程序推进更新实例属性
        self.sj=0
        self.zt='sheng'
        self.tw=[]

    def cook(self,time):#定义烤地瓜方法
        self.sj +=time
        if 0<=self.sj<3:
            self.zt='sd'
        elif 3<=self.sj<5:
            self.zt='bsbs'
        elif 5<=self.sj<8:
            self.zt='ggs'
        elif 8<=self.sj:
            self.zt='hule'
    def tiaoliao(self, tl):#定义添加调料方法,并调用该实例方法
        self.tw.append(tl)
    def __str__(self):# 书写str魔法方法,用于输出对象状态
        return f'烤了{self.sj}分钟,状态是{self.zt}'
digua1=DiGua()
print(digua1)
digua1.cook(2)
print(digua1)
digua1.tiaoliao('酱油')
print(digua1)
digua1.cook(2)
digua1.tiaoliao('油')
print(digua1)

1.因为可能多种调料,所以调料用列表形式存储

2.注意快捷输入__ init __ 时不要错写成 __ int __

在这里插入图片描述

搬家具

需求:

1.房子类
实例属性
房子地理位置
房子占地面积
房子剩余面积
房子内家具列表
实例方法
容纳家具
显示房屋信息
2.家具类
家具名称
家具占地面积

class Jiaju():
    def __init__(self,name,area):
        self.jiaju_name=name
        self.jiaju_area=area
class Home():
    def __init__(self,address,area):
        self.home_address=address
        self.home_area=area
        self.home_area_free=area
        self.home_jiaju=[]
    def __str__(self):
        return f'房子坐落于{self.home_address},占地面积{self.home_area}平方米,剩余面积{self.home_area_free}平方米,配备有{self.home_jiaju}'

    def add_jiaju(self,item):
        if self.home_area_free>=item.jiaju_area:
            self.home_jiaju.append(item.jiaju_name)
            self.home_area_free-=item.jiaju_area

            def __str__(self):
                return f'房子坐落于{self.home_address},占地面积{self.home_area}平方米,剩余面积{self.home_area_free}平方米,配备有{self.home_jiaju}'
        else:
            print('剩余面积不够了')


bed =Jiaju('双人床',12)
sofa=Jiaju('沙发',5000)

fangzi1=Home('北京',1000)
print(fangzi1)
fangzi1.add_jiaju(bed)
print(fangzi1)
fangzi1.add_jiaju(sofa)
print(fangzi1)

继承

面向对象三大特性:

  1. 封装
  2. 继承
  3. 多态
class  人
    吃
    喝
    玩
    拉
    睡
class 老师
  上课
  备课
class 工程师
  上班
  加班

继承的作用: 减少代码的冗余,便于功能的升级(原有的功能进行完善)与扩展(原没有的功能进行添加)

class People(object):
  def __init__(self,name,age):
    self.name=name
    self.age=age
  def eat(self):
    print("come to eat,{}".format(self.name))
  def drink(self):
    print("come to drink,{}".format(self.name))
class Man(People): # 表示Man类继承父类(基类,超类)People
  pass
class Woman(People): # 表示Woman类继承父类(基类,超类)People
  pass
m1=Man("zhangsan",16)
m1.eat() # 继承了父类,就可以调用父类的方法
m1.drink() # 继承了父类,就可以调用父类的方法
w1=Woman("lisi",18)
w1.eat() # 继承了父类,就可以调用父类的方法
w1.drink() # 继承了父类,就可以调用父类的方法

方法重写

示例: 在子类里重写父类的方法

class People(object):
  def __init__(self,name,age):
    self.name=name
    self.age=age
  def eat(self):
     print("come to eat,{}".format(self.name))
  def drink(self):
    print("come to drink,{}".format(self.name))
class Man(People):
  def drink(self): # 在子类里写了一个和父类相同的方法,那么对这个子类实例化,调用此方法,子类方法会优先生效(方法重写)
#    People.drink(self) # 可以在子类里继续调用父类的方法
    if self.age>=18: # 下面这是可以在原来的基础上再增加额外的功能代码
      print("you can drink!")
    else:
      print("you can not drink!")
class Woman(People):
  pass
m1=Man("zhangsan",16)
m1.drink()

子类重新构造属性

class People(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def eat(self):
        print("come to eat,{}".format(self.name))
    def drink(self):
        print("come to drink,{}".format(self.name))
class Man(People):
    def drink(self):
#       People.drink(self)
        if self.age>=18:
            print("you can drink!")
        else:
            print("you can not drink!")
class Woman(People):
    def __init__(self,name,age,bra_size): # 如果我的子类有新属性,需要在这里用构造函数重新构造,但需要和原父类的属性对应
        People.__init__(self,name,age)
        # 经典类写法;换成super(Woman,self).__init__(name, age)这句也一样(新式类写法)
        self.bra_size = bra_size
w1=Woman("lisi",18,"D")
w1.eat()
w1.drink()

多层继承

示例: 多层继承例一

class Grandfather():
      def house(self): # 爷爷类的方法
            print("a big house!")
class Father(Grandfather): # 爸爸类继承爷爷类
      def car(self):
            print("a cool car!")
class child(Father): # 孩子类继承爸爸类
      pass
p1=child() # 实例化一个孩子
p1.house() # 这个孩子对象可以调用爷爷的方法

示例: 多层继承例二

class People():
        def __init__(self, name, sex):
                self.name = name
                self.sex = sex
class Love(People):
        def fall_in_love(self,obj):
                if self.sex == "男":
                        print("{}向{}求婚".format(self.name,obj.name))
                elif self.sex == "女":
                        print("{}要给{}生猴子".format(self.name,obj.name))
                else:
                        print("性别输入有误")
class Man(Love):
        pass
class Woman(Love):
        pass
m1=Man("张三","男")
w1=Woman("李四","女")
m1.fall_in_love(w1)
w1.fall_in_love(m1)

多继承

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

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):
    pass
daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
#[新东方的韭菜炒蛋的食谱]
#运用[新东方的韭菜炒蛋的食谱]制作韭菜炒蛋

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

super()调用父类方法

class A:
    def spam(self):
        print('A.spam')

class B(A):
    def spam(self):
        print('B.spam')
        super().spam()  # Call parent spam()
a=B()
a.spam()
#B.spam
#A.spam

super() 函数的一个常见用法是在 __init__() 方法中确保父类被正确的初始化了

私有属性与私有方法

一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
python没有像其它语言那样有public,private等关键词来修饰,而是在变量前加__来实现私有

示例:

class People(object):
  __country="china" # 前面加上__,那么就做成了私有属性,就不能被类的外部直接调用
  def __init__(self,name,sex):
    self.name=name
    self.__sex=sex # 前面加上__,那么就做成了私有属性,就不能被类的外部直接调用
  def __info(self): # 前面加上__,那么就做成了私有方法,就不能被类的外部直接调用
    print(self.name,self.sex)
p1=People("zhangsan","man")
# print(p1.sex)
# print(p1.__sex)
# print(p1.country)
# print(p1.__country)
# p1.info()
# p1.__info() # 这六句单独打开注释验证,都会报错。不能调用私有属性和私有方法

获取和修改私有属性值

如果类的外部需要调用到私有属性的值,可以对私有属性单独定义一个类的方法,让实例通过调用此方法来
调用私有属性(私有方法同理)

示例:

class People(object):
  __country="china"
  def __init__(self,name,sex):
    self.name=name
    self.__sex=sex
   
  def __info(self):
    print(self.name,self.__sex)
  def show_sex(self):
    print(self.__sex)
  def show_country(self):
    print(self.__country)
  def show_info(self):
    People.__info(self)
p1=People("zhangsan","man")
p1.show_sex()
p1.show_country()
p1.show_info()

二十三、面向对象(二)

  • 封装
    • 将属性和方法书写到类的里面的操作即为封装
    • 封装可以为属性和方法添加私有权限
  • 继承
    • 子类默认继承父类的所有属性和方法
    • 子类可以重写父类属性和方法
  • 多态
    • 传入不同的对象,产生不同的结果

多态

多态: 一类事物的有多种形态。如水蒸汽,水,冰。

回顾下我们前面讲过: Python是强类型的动态解释型语言,这里的动态其实就是多态。

python是变量本身是没有类型的,变量的类型是由赋的值所决定的。值是int,变量就是int; 值是str,变量类型就
是str。这其实就是一种多态。

python崇尚鸭子类型(ducking type): 鸭子类型是动态类型的一种风格。“当看到一只鸟走起来像鸭子、游泳起来像
鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 在鸭子类型中,关注的不是对象的类型本身,而是它是
如何使用的。

作用: 接口统一

实现步骤:
定义父类,并提供公共方法
定义子类,并重写父类方法
传递子类对象给调用者,可以看到不同子类执行效果不同

示例:

class Animal(object):
 def jiao(self):
    pass
class Dog(Animal):
  def jiao(self):# 子类重写父类同名方法
    print("wang wang...")
class Cat(Animal):
  def jiao(self):
    print("miao miao...")
d1=Dog()
c1=Cat()
d1.jiao() # 实例接类的方法来调用,结果是狗叫
c1.jiao() # 实例接类的方法来调用,结果为猫叫

示例:

class Animal(object):
 def jiao(self):
    pass
class Dog(Animal):
  def jiao(self):
    print("wang wang...")
class Cat(Animal):
  def jiao(self):
    print("miao miao...")
def jiao(obj):
  obj.jiao()
d1=Dog()
c1=Cat()
jiao(d1) # 调用方式统一
jiao(c1) # 调用方式统一

类属性和实例属性

类属性
  • 类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有。
  • 类属性可以使用类对象或实例对象访问。
class Dog(object):
    tooth = 10
    wangcai = Dog()
    xiaohei = Dog()

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

类属性的优点:

  • 类的实例记录的某项数据始终保持一致时,则定义类属性。
  • 实例例属性要求每个对象为其单独开辟一份内存空间来记录数据,而类属性为全类所共有仅占用一份内存,更加节省内存空间。
修改类属性

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

class Dog(object):
    tooth = 10
wangcai = Dog()
xiaohei = Dog()

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

# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
wangcai.tooth = 20
print(Dog.tooth)	# 12
print(wangcai.tooth)	# 20
print(xiaohei.tooth)	# 12
实例属性
class Dog(object):
    def init (self): 
        self.age = 5
    def info_print(self):
        print(self.age)
wangcai = Dog() print(wangcai.age)	# 5
# print(Dog.age)	# 报错:实例属性不能通过类访问
wangcai.info_print()	# 5
        

类方法和静态方法

类方法

特点:

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

使用场景 :

  • 当方法中需要使用类对象 (如访问私有类属性等)时,定义类方法
  • 类方法一般和类属性配合使用
class Dog(object):
    __tooth = 10
    @classmethod
    def get_tooth(cls):
        return cls.__tooth
wangcai = Dog()
result = wangcai.get_tooth()
print(result) # 10
静态方法

特点:

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

使用场景 :

  • 当方法中既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
class Dog(object):
    @staticmethod
    def info_print():
        print('这是一个狗类,用于创建狗实例....')
wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()

二十四、异常

异常的写法

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

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

try:
    f = open('test.txt', 'r')
except:
    f = open('test.txt', 'w')
捕获指定异常
try:
    可能发生错误的代码
except 异常类型:
    如果捕获到该异常类型执行的代码
try:
    print(num)
except NameError:
    print('有错误')

注意:

  1. 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
  2. 一般try下方只放一行尝试执行的代码。
捕获多个指定异常

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

try:
    print(1/0)
except (NameError, ZeroDivisionError):
    print('有错误')
捕获异常描述信息
try:
    print(num)
except (NameError, ZeroDivisionError) as result:
    print(result)
捕获所有异常

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

try:
    print(num)
except Exception as result:
    print(result)
异常的else

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

try:
    print(1)
except Exception as result:
    print(result)
else:
    print('我是else,是没有异常的时候执行的代码')
异常的finally

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

try:
    f = open('test.txt', 'r')
except Exception as result:
    f = open('test.txt', 'w')
else:
    print('没有异常')
finally:
    f.close()

异常的传递

需求:

  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("没有这个文件")

自定义异常

在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()

二十五、模块和包

模块

​ Python 模块(Module),是一个Python文件,以 .py 结尾,包含了Python对象定义和Python语句。模块能定义函数,类和变量,模块里也能包含可执行的代码。

导入模块的方式

  • import 模块名
  • from 模块名 import 功能名
  • from 模块名 import *
  • import 模块名 as 别名
  • from 模块名 import 功能名 as 别名
# # 1. 导入模块
# import 模块名
# import 模块名1, 模块名2...
# # 2. 调用功能
# 模块名.功能名()

import math
print(math.sqrt(9))

# from 模块名 import 功能1, 功能2, 功能3...

from math import sqrt
print(sqrt(9))

#from 模块名 import *

from math import *
print(sqrt(9))


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

# 模块别名
import time as tt
tt.sleep(2)
print('hello')
# 功能别名
from time import sleep as sl
sl(2)
print('hello')
制作模块

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

1.定义模块

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

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

2.测试模块

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

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

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

def testA(a, b):
    print(a + b)
# 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行testA函数调用
if __name__ == '__main__':
    testA(1, 1)

3.调用模块

import my_module1
my_module1.testA(1, 1)

4.注意事项

如果使用 from … import … 或 from … import * 导入多个模块的时候,且模块内有同名功能。当调用这个同名功能的时候,调用到的是后面导入的模块的功能

# 模块1代码
def my_test(a, b):
    print(a + b)
# 模块2代码
def my_test(a, b):
    print(a - b)
# 导⼊入模块和调⽤用功能代码
from my_module1 import my_test
from my_module2 import my_test
# my_test函数是模块2中的函数
my_test(1, 1)
模块定位顺序

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

  1. 当前目录
  2. 如果不在当前目录, Python则搜索在shell变量PYTHONPATH下的每个目录
  3. 如果都找不到, Python会察看默认路径.UNIX下,默认路径一般为/usr/local/lib/python/

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

注意 :

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

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

__ all __

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

my_module1模块代码

__all__ = ['testA']
def testA():
    print('testA')
def testB():
    print('testB')

导入模块的文件代码

from my_module1 import *
testA()
testB()

在这里插入图片描述

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

制作包

New] — [Python Package] — 输入包名 — [OK] — 新建功能模块(有联系的模块)。
注意:新建包后,包内部会自动创建 __ init __.py 文件,这个文件控制着包的导入行为。

1.新建包 mypackage

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

3.模块内代码如下

# my_module1
print(1)
def info_print1():
    print('my_module1')
# my_module2
print(2)
def info_print2():
print('my_module2')
导入包

方法一:

import 包名.模块名
包名.模块名.目标

import my_package.my_module1
my_package.my_module1.info_print1()

方法二:

from 包名 import *
模块名.目标

from my_package import *
my_module1.info_print1()
  • 9
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值