AI Python基础(面向对象之后)
人工智能 Python基础
一、面向对象
面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事
1、类和对象
类和对象的关系:用类去创建一个对象,先有类再有对象,一个类可以创建多个对象,不同对象的self地址不相同
1.1、定义类
创建对象:对象名 = 类名
对象方法/实例方法:对象名.wash( )
class Machine():
def wash(self):
print('洗衣服')
Haier = Machine()
print(Haier)
Haier.wash()
类里面的self:注意到我们创建类的时候,函数参数会自动填充self,由于打印对象和打印self得到的内存地址相同,所以self指的是调用该函数的对象,在上面的代码案例中,self就指的是Haier
1.2、对象属性操作
以下三个步骤,是要先添加对象属性,然后分类外类里,来获取对象属性
1.2.1、类外添加对象属性
语法:对象名.属性名 = 值
class machine():
def wash(self):
print('洗')
Haier = machine()
Haier.wash()
Haier.width = 400
Haier.height = 300
1.2.2、类外面获取对象属性
语法:对象名.属性名
class machine():
def wash(self):
print('洗')
Haier = machine()
Haier.width = 400
print(f'Haier的宽度是{Haier.width}')
1.2.3、类里面获取对象属性
语法:self.属性名
class machine():
def print_info(self):
print(f'洗衣机的宽度是{self.width}')
Haier = machine()
Haier.width = 400
Haier.print_info()
1.3、魔法方法
在Python中,__xx__( )的函数叫做魔法方法,指的是具有特殊功能的函数
1.3.1、__init__( )
__init__( )魔法方法,用于初始化对象,在创建一个对象时默认被调用,不需要手动调用
class Machine():
def __init__(self):
self.width = 400
self.height = 300
def print_info(self):
print(f'洗衣机的宽是{self.width},高是{self.height}')
Haier = Machine()
Haier.print_info()
带参数的__init__( ),在括号里,self是默认的自带的,代表对象本身,我们如果想要输出显示洗衣机的名字,不能直接在print_info里输入{self},最好的方法是把name也当作参数一起传入init,带参数的__init__( )方便一个类创建多个对象
class Machine():
def __init__(self,name,width,height):
self.width = width
self.height = height
self.name = name
def print_info(self):
print(f'洗衣机{self.name}的宽度是{self.width}')
Haier = Machine('Haier',10,20)
Haier.print_info()
# result:洗衣机Haier的宽度是10
1.3.2、__str__( )
当我们print对象名的时候,输出的默认是对象的内存地址,如果定义了__str__方法,那么就会打印从这个方法中return的数据
class Machine():
def __str__(self):
return '这是一个洗衣机'
Haier = Machine()
print(Haier)
1.3.3、__del__( )
当删除对象时,python解释器会默认调用__del__( )方法,其实即使不使用del删除对象,我们等程序运行结束时,系统会释放内存,这个时候也会自动调用__del__( )
class Machine():
def __str__(self):
return '这是一个洗衣机'
def __del__(self):
print(f'已经删除')
Haier = Machine()
print(Haier)
# result:
# 这是一个洗衣机
# 已经删除
2、案例
2.1、烤地瓜
# 定义地瓜类:初始化属性,被烤和添加调料的方法,显示对象信息的str
class SweetPotato():
def __init__(self):
self.cook_time = 0 # 烤的时间
self.condition = '生的' # 烤的状态
self.condiments = [] # 调料列表
def cook(self,time): # 烤的方法
self.cook_time += time
if 0 <= self.cook_time < 3:
self.condition = '生的'
elif 3 <= self.cook_time < 5:
self.condition = '半生'
elif 5 <= self.cook_time < 8:
self.condition = '熟了'
elif self.cook_time >= 8:
self.condition = '糊了'
def add_condiments(self,condiment): # 添加调料方法
self.condiments.append(condiment)
def __str__(self): # 输出对象状态
return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.condition},添加的调料有{self.condiments}'
# 创建对象并调用对应的实例方法
digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
digua1.add_condiments('pepper')
print(digua1)
digua1.cook(4)
digua1.add_condiments('sausage')
print(digua1)
2.2、搬家具
这里我来解释一下,为什么在add_furniture那边可以这么自然的用item.name这种语句呢,是因为我在下面已经先创建了家具类的对象bed,我已经确定了bed是一个家具类,所以我可以使用家具类里的参数
class Furniture(): # 家具类
def __init__(self,name,area):
self.name = name
self.area = area
class House(): # 房屋类
def __init__(self,address,area):
self.address = address
self.area = area
self.free_area = area
self.furniture = []
def add_furniture(self,item):
if self.free_area >= item.area:
self.furniture.append(item.name)
self.free_area -= item.area
else:
print('放不下了')
def __str__(self):
return f'房子地址是{self.address},占地面积是{self.area},剩余面积{self.free_area},里面有家具{self.furniture}'
bed = Furniture('双人床',30)
sofa = Furniture('沙发',80)
home1 = House('上海',100)
print(home1)
home1.add_furniture(sofa)
print(home1)
home1.add_furniture(bed)
print(home1)
房子地址是上海,占地面积是100,剩余面积100,里面有家具[]
房子地址是上海,占地面积是100,剩余面积20,里面有家具['沙发']
放不下了
房子地址是上海,占地面积是100,剩余面积20,里面有家具['沙发']
3、继承
Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法
语法class B(父类),在Python中,所有类默认继承object类,object类是顶级类或基类,其他子类叫做派生类
class A(): # 父类
def __init__(self):
self.a = 1
def info_print(self):
print(self.a)
class B(A): # 子类
pass
test = B()
test.info_print()
3.1、单继承
子类只继承一个父类,上面这个继承的例子就是单继承
3.2、多继承
子类继承多个父类,一个类有多个父类的时候,如果属性和方法同名,默认使用第一个父类的同名属性和方法,不同名则都继承到了
class A():
def __init__(self):
self.a = 2
def info_print(self):
print(self.a)
class B():
def __init__(self):
self.a = 1
def info_print(self):
print(self.a)
class C(A,B):
pass
ivy = C()
ivy.info_print()
# result:2
4、子类重写父类属性和方法
如果子类和父类拥有同名属性和方法,优先调用的是子类的
class Master():
def __init__(self):
self.kongfu = '师傅'
def make(self):
print(f'这是{self.kongfu}方法')
class School():
def __init__(self):
self.kongfu = '学院'
def make(self):
print(f'这是{self.kongfu}方法')
class prentice(Master, School):
def __init__(self):
self.kongfu = '独创'
def make(self):
print(f'这是{self.kongfu}方法')
ivy = prentice()
ivy.make()
4.1、拓展:mro顺序
子类.__mro__ 快速查看子类继承的父类和父类之间的层级关系
按照上面的例子,我们可以得出结果如下
print(prentice.__mro__)
# result:
(<class '__main__.prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
4.2、子类调用父类的同名方法和属性
在同名的情况下,注意了,我们在写子类的时候,如果在子类里写了自己的属性和方法,然后我们创建了一个子类对象之后,优先调用的就是子类方法,但是为了不丧失父类方法的这个选择,我们可以多def几个有关父类的方法,并在方法中初始化父类属性,像这样
def master_make(self):
Master.__init__(self)
Master.make(self)
def school_make(self):
School.__init__(self)
School.make(self)
4.3 super( )调用父类方法
super就是一根链条
class A: ... class A: ...
class B(A): ... class B( ): ...
class C(B): ... class C(A, B): ...
这两种情况,第一个是单继承,单链,C-B-A,第二个是多继承,顺序是C-A-B(优先第一个父类),super就相当于两节火车之间的链条,如果每一个类之间都有super,那一定可以串联起来,如果不想串联这么多,那一定要按照mro顺序来写super,在第一种情况,我们在C下面写super就是找到B,第二种情况我们在C下面写super就是找到A
方法一:super(当前类名,self).函数( )
方法二:super( ).函数( )
5、私有属性和方法
设置私有属性和方法:在属性名和方法名前面加上两个下划线__
在这里会报错,无法继承给B
class A():
def __init__(self):
self.__money = 100
class B(A):
pass
ivy = B()
print(ivy.__money)
在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性,注意!!这个是工作习惯,函数名可以改变,但是一般就是用这两个
!!注意,比如我们的私有属性在A里面,我们就在A里面def获取和set函数
class A():
def __init__(self):
self.__money = 100
def get_money(self):
return self.__money
def set_money(self,money):
self.__money = money
class B(A):
pass
ivy = B()
print(ivy.get_money())
ivy.set_money(200)
print(ivy.get_money())
6、多态
多态指的是一类事物有多种形态
多态是一种调用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
步骤:定义父类,并提供公共方法;定义子类并重写父类方法;传递子类对象给调用者,可以看到不同子类执行效果不同
class Dog():
pass
class ArmyDog(Dog):
def work(self):
print("追击敌人")
class DrugDog(Dog):
def work(self):
print('追查毒品')
class Police():
def job(self,dog):
dog.work()
ad = ArmyDog()
dd = DrugDog()
ivy = Police()
ivy.job(dd)
7、类属性及相关方法
下面这个就是类属性,不要和self.width = 100这样的搞混了,这种self是写在__init__里的,是实例属性,访问类属性可以通过对象去访问,也可以通过类去访问
在记录某项数据的时候,如果这个数据要一直保持一致,则定义类属性,为什么?因为实例属性要求每个对象为其单独开辟一份内存空间来记录数据,类属性为全类共有的,仅占用一份内存
class Dog():
tooth = 10
a = Dog()
b = Dog()
print(a.tooth)
print(b.tooth)
print(Dog.tooth)
7.1、修改类属性
类属性只能通过类修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个同名的实例属性,类属性就相当于一个大的东西,牵一发而动全身的东西
class Dog():
tooth = 10
a = Dog()
Dog.tooth = 20
print(a.tooth)
# result:20
7.2、类方法
需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类,一般以cls作为第一个参数
当方法中需要使用类对象,比如访问私有类属性时,定义类方法,类方法一般和类属性配合使用
class Dog():
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth
a = Dog()
print(a.get_tooth())
7.3、静态方法
静态方法需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象,也不需要传递实例对象,也就是形参没有self/cls,当方法中既不需要使用实例也不需要使用类时,创建静态方法
class Dog():
@staticmethod
def print_info():
print("这是一个静态方法")
a = Dog()
a.print_info()
二、异常
当检测到一个错误之后,解释器就无法继续执行了,出现错误提示,这就是异常
如果你不确定你写的这一句代码会不会报错,可以把这句代码放到异常语句里书写
1、异常介绍
try:
可能发生错误的代码
except:
如果出现异常执行的代码
try:
open('1.txt','r')
except:
open('1.txt','w')
异常类型
这里的异常类型就是NameError,异常类型就是最后一排,冒号前面的东西

1.1、捕获指定异常
如果尝试执行的代码的异常类型和要捕获的异常类型不一样,则无法捕获异常,一般try下面只放一条尝试执行的代码
try:
可能发生错误的代码
except 异常类型:
如果捕捉到该异常类型执行的代码
try:
print(num)
except NameError:
print("NameError")
1.2、捕获多个异常类型
当捕获多个异常时,把要捕获的异常的名字写在except后面,用元组的形式存放
try:
print(num)
except (ZeroDivisionError,NameError):
print("有错误")
1.3、捕获异常描述信息
在这里"name 'num' is not defined.这个是异常描述信息,以下代码,result是一个变量,print就是打印异常描述信息

try:
print(num)
except (ZeroDivisionError,NameError) as result:
print(result)
1.4、捕获所有异常
Exception是所有程序异常类的父类
try:
print(num)
except Exception as result:
print(result)
1.5、异常的else
else表示的是如果没有异常的时候要执行的代码
try:
print(1)
except Exception as result:
print(result)
else:
print('未发现异常')
# result:
1
未发现异常
1.6、异常的finally
finally表示的是无论是否异常都要执行的代码,例如关闭文件
try:
f = open("test.txt","r")
except Exception as result:
f = open("test.txt","w")
else:
print('未发现异常')
finally:
f.close()
1.7、命令提示符运行py文件
在我的电脑中,找到存放py代码项目的那个路径,删除掉之后输入cmd,就会进入到cmd界面,然后输入python test.py,就可以运行,为什么输入python而不是python3呢,因为我的python已经是3.x.x版本了

2、异常的传递
在命令提示符中运行ctrl+c停止才会报错,pycharm中不属于报错,import time的意义是要使用time模块里的sleep函数,让程序运行的慢一点,不然这个程序一瞬间就执行完了,我们没有停止的机会来测试这个案例
import time
try:
f = open('test.txt','r')
try:
while True:
con = f.readline()
if len(con) == 0:
break
time.sleep(3)
print(con)
except:
print('程序被意外终止')
except:
print('文件不存在')

3、自定义异常
抛出这个自定义异常用raise
将不满足程序逻辑要求的代码,捕获异常,比如要求输入3位数字密码,只输入了2位,然后会报异常,把这个异常当作一个类,把他定义出来
!!:可以这样理解,其实这个程序本身是没有异常的,但是因为不符合你的业务逻辑,所以定义了一个异常类,把这个不符合逻辑的代码归类为异常,以便可以执行except里面的代码
class InputerNumError(Exception):
def __init__(self, len,min_len):
self.len = len
self.min_len = min_len
def __str__(self):
return f'你输入的密码长度为{self.len},密码至少要{self.min_len}位'
def main():
try:
num = input('请输入密码:')
if len(num) < 3:
raise InputerNumError(len(num),3)
except Exception as e:
print(e)
else:
print('密码输入完成')
main()
三、模块
Python模块,就是一个python文件,以.py结尾,我们可以在左边的外部库里找到random.py文件,我们import 模块,就是导入一个py文件
1、导入模块
第一种 import 模块名
import 模块名
模块名.功能名()
import math
print(math.sqrt(9)) # sqrt:square root 平方根
第二种 from 模块名 import 功能1,功能2......,这种方式导入模块时,调用不用math.sqrt()了,直接写就行
from math import sqrt
print(sqrt(9))
第三种 from 模块名 import *
from math import *
print(sqrt(9))
1.1、定义别名
模块定义别名 import 模块名 as 别名,定义了别名之后,就不能再用原名,不然报错
import math as mt
print(mt.sqrt(4))
功能定义别名 from 模块名 import 功能 as 别名,定义别名之后,不能再用原名
from math import sqrt as aa
print(aa(4))
2、模块制作
每个python文件都可以作为一个模块,模块的命名必须符合标识符命名规则
模块制作分三步 定义模块--测试模块--调用模块
定义、测试模块

如果就这样把测试的代码留在上面,那么在别的文件导入这个my_module1作为模块的时候,也会运行这个测试代码,所以这个测试代码只能在模块内运行
我们引入__name__,这个__name__是系统变量,是模块的标识符,如果在自己本来的文件下面,则等于__main__,如果在别的文件下面,则等于别的文件的文件名

3、模块定位顺序
tip1:自己的文件名不要和已有的模块名重复,否则导致模块功能无法使用;
当导入一个模块时,Python解析器对模块位置搜索的顺序是从当前目录开始,到shell变量PYTHONPATH下的每个目录,也就是说,如果我们在当前目录下创建一个空的random文件,导入random模块的时候会优先导入这个,导致报错
tip2:使用from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能,以下是案例,这个会报错,这里会优先调用函数sleep而不是模块中的sleep
from time import sleep
def sleep():
print("Sleeping...")
sleep(2)
4、__all__列表
module代码
__all__ = ['testA']
def testA(a,b):
print(a+b)
def testB(a,b):
print(a-b)
自身代码
from my_module1 import *
testA(2,3)
testB(3,4) # 报错
!!注意这个时候会报错的,因为在module模块中,all列表里只有testA这个元素,所以在导入这个模块时,也只能导入testA这个功能
5、Python中的包
包将有联系的模块组织在一起,放到同一个文件夹下,并在这个文件夹创建一个名字为__init__.py
的文件,这个文件夹就称为包
5.1、制作包
[New]--[Python Package]--输入包名--[OK]--新建功能模块(有联系的模块)
新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为
5.2、导入包
方法一:import 包名.模块名 包名.模块名.目标
import mypackage.my_module1
mypackage.my_module1.print_info()

方法二:必须在__init__.py文件中添加__all__ = [],控制允许导入的模块列表
from 包名 import * 模块名.目标
和上面的__all__列表一样,没有允许的就不能调用
四、学生管理系统(面向对象)

student.py
class Student(object):
def __init__(self, name, gender,tel):
self.name = name
self.gender = gender
self.tel = tel
def __str__(self):
return f'姓名:{self.name} 性别:{self.gender} 手机号:{self.tel}'
aa = Student('xjj','男','324')
print(aa)
managerSystem.py
from StudentManagerSystem.student import Student
class StudentManager():
def __init__(self):
# 存储学员数据
self.student_list = []
def run(self):
# 加载学员数据
self.load_student()
while True:
self.show_menu()
num = int(input('请输入需要的序号:'))
if num == 1: # 添加
self.add_student()
elif num == 2: # 删除
self.del_student()
elif num == 3: # 修改
self.modify_student()
elif num == 4: # 查询
self.search_student()
elif num == 5: # 显示
self.show_student()
elif num == 6: # 保存
self.save_student()
elif num == 7:
break
@staticmethod
def show_menu():
print('请选择功能-------------------')
print('1、添加')
print('2、删除')
print('3、修改')
print('4、查询')
print('5、显示')
print('6、保存')
print('7、退出')
print('-'* 20)
def add_student(self):
name = input('输入姓名:')
gender = input('输入性别:')
tel = int(input('输入手机号:'))
student = Student(name, gender, tel)
self.student_list.append(student)
print(student)
def del_student(self):
del_name = input('输入要删除的姓名:')
for i in self.student_list:
if i.name == del_name:
self.student_list.remove(i)
break
else:
print('没有找到用户')
print(self.student_list)
def modify_student(self):
print('修改')
def search_student(self):
print('查询')
def show_student(self):
print('显示')
def save_student(self):
print('保存')
def load_student(self):
print('加载')
main.py
from managerSystem import *
if __name__ == '__main__':
manager1 = StudentManager()
manager1.run()
更多推荐



所有评论(0)