面相对象程序设计与模块
两大编程思想-面向过程和面向对象
自定义类和创建自定义类的对象
a=10
b=9.8
s='hello'
print(type(a))
print(type(b))
print(type(s))#编写-个Person
class Person():pass#编写一个Cat类
class Cat():pass#编写一个Dog类
class Dog:pass#编写一个Student类
class Student:pass#创建类的对象
#对象名=类名()#创建一个Person类型的对象
per=Person() #per就是Person类型的对象
c=Cat()# c就是Cat类型的对象
d=Dog()# d就是Dog类型的对象
stu=Student()#stu就是Student类型的对象print(type(per))
print(type(c))
print(type(d))
print(type(stu))
类的组成
class Student:#类属性:定义在类中,方法外的变量school='北京XXX教育'#初始方法方法def __init__(self,xm,age):# xm,age是方法的参数,是局部变量,xm,age的作用域是整个__init__方注self.name=xm #=左侧是实例网性,xm是局变量 ,将局部变量的值xm赋值给实例属性self.nameself.age=age #实例的名称和局部变量的名称可以相同#定义在类中的雨数,称为方法,自带一个参数selfdef show(self):print(f'我叫:{self.name},今年:{self.age}岁了')# 静态方法@staticmethoddef sm():#print(self.name)#self.show()print('这是一个静态方法,不能调用实例属性,也不能调用实例方法')@classmethoddef cm(cls):#cls-->class的简写#print(self.name)#self.show()print('这是一个类方法,不能调用实例属性,也不能调用实例方法')#创建类的对象
stu=Student('ysj',18)#为什么传了两个参数,因为__init__方法中,有两个形参,self,是自带的参数,无需手动传入
#实例属性,使用对象名进行打点调用的
print(stu.name,stu.age)
#类属性 ,直接使用类名,打点调用
print(Student.school)#实例方法,使用对象名进行打点调用
stu.show()#类方法,@classmethod进行修饰的方法,直接使用类名打点调用
Student.cm()# 静态方法 @staticmethod进行修饰的方法,直接使用类名打点调用
Student.sm()
使用类模板创建N多个对象
class Student:#类属性:定义在类中,方法外的变量school='北京XXX教育'#初始方法方法def __init__(self,xm,age):# xm,age是方法的参数,是局部变量,xm,age的作用域是整个__init__方注self.name=xm #=左侧是实例网性,xm是局变量 ,将局部变量的值xm赋值给实例属性self.nameself.age=age #实例的名称和局部变量的名称可以相同#定义在类中的雨数,称为方法,自带一个参数selfdef show(self):print(f'我叫:{self.name},今年:{self.age}岁了')#根据"图纸"可以创建出N多个对象
stu=Student('ysj',18)
stu2=Student('陈梅梅',20)
stu3=Student('马丽', 21)
stu4=Student('Marry',23)#等号的右网都是Student
print(type(stu))
print(type(stu2))
print(type(stu3))
print(type(stu4))Student.school='派森教育'#给类的关属性赋值
#将学生对象存储到列表中
lst=[stu,stu2,stu3,stu4]# 列表中的元素是Student类型的对象
for item in lst:#item是列表中的元素,是Student类型的对象item.show()#对象名打点调用实例方法
动态绑定属性和方法
class Student:#类属性:定义在类中,方法外的变量school='北京XXX教育'#初始方法方法def __init__(self,xm,age):# xm,age是方法的参数,是局部变量,xm,age的作用域是整个__init__方注self.name=xm #=左侧是实例网性,xm是局变量 ,将局部变量的值xm赋值给实例属性self.nameself.age=age #实例的名称和局部变量的名称可以相同#定义在类中的雨数,称为方法,自带一个参数selfdef show(self):print(f'我叫:{self.name},今年:{self.age}岁了')#创建两个Student类型的对象
stu=Student( 'ysj', 18)
stu2=Student( '陈梅梅', 20)
print(stu.name,stu.age)
print(stu2.name,stu2.age)#为stu2动态绑定一个实例属性
stu2.gender='男'
print(stu2.name,stu2.age,stu2.gender)
#print(stu.gender)#AttributeError: 'Student' object has no attribute 'gender'
# #动态绑定方法
def introduce():print('我是一个普通的函数,我被动态绑定成了stu2对象的方法')
stu2.fun=introduce#函数的一个赋值,
# #fun就是stu2对象的方法
#调用
stu2.fun()
Python中的权限控制
class Student():#首尾双下划线def __init__(self,name,age,gender):self._name=name #self._name受保护的,只能本类和了类访问self.__age=age #self.-_age表示私有的,只能类本身去访问self.gender=gender#普通的实例械性,类的内部、外部、及于类都可以访问def _fun1(self):print('子类及本身可以访问')def __fun2(self): # 私有的print('只有定义的类可以访问')def show(self): # 普通的实例方法self._fun1()# 类本身访问受保护的方法self.__fun2()#类本身访间私有方法print(self._name)#受保护的实例属性print(self.__age)#私有的实例属性# 创建一个学生类的对象
stu=Student('陈梅梅',20,'女')
#类的外部
print(stu._name)
#print(stu.__age) # AttributeError: 'student'object has no attribute ' _age'. Did you mean: '_name'i#调用受保护的实例方法
stu._fun1()#子类及本身可以访问
#私有方法
# stu.__fun2()#AttributeError:'Student' object has no attributefun2'. Did you mean:'_fun1'?#私有的实例属性和方法是真的不能访问吗?
print(stu._Student__age)# 为什么可以这样访问呢?
stu._Student__fun2()print(dir(stu))
属性的设置
class Student:def __init__(self, name, gender):self.name = nameself.__gender = gender # self.-_gender 是私有的实例属性# 使property 修改方法,将方法转成属性使用@propertydef gender(self):return self.__gender# 将我们的gender这个属性设置为可写属性@gender. setterdef gender(self,value):if value!='男'and value !='女':print('性别有误,已将性别默认设置为男')self.__gender='男'else:self.__gender = valuestu = Student('陈梅梅', '女')
print(stu.name, '的性别是:', stu.gender) # stu.gender就会去执行stu.gender()#尝试修改属性值
# stu.gender='y’#AttributeError: property 'gender'of 'Student' object has no setter
stu.gender = '其它'
print(stu.name, '的性别是:',stu.gender)
继承的概念
class Person:#默认继承了objectdef __init__(self,name,age):self.name=nameself.age=agedef show(self):print(f'大家好,我叫:{self.name},我今年:{self.age}岁')#Student继承Person类
class Student(Person):#编写初始化的方法def __init__(self,name,age,stuno):super().__init__(name,age)# 调用父类的初始化方法self.stuno=stuno#Doctor继承Person类
class Doctor(Person):# 编写初始化方法def __init__(self,name,age,department):super().__init__(name,age)self.department=department# 创建第一个子类对象
stu=Student('陈梅梅',20,'1001')
stu.show()doctor=Doctor('张--', 32,'外科')
doctor.show()
Python中的多继承
class FatherA():def __init__(self,name):self.name=namedef showA(self):print('父类A中的方法')class FatherB():def __init__(self,age):self.age=agedef showB(self):print('父类B中的方法')#多继承
class Son(FatherA,FatherB):def __init__(self,name,age,gender):#需要调用两个父类的初始化方法FatherA.__init__(self,name)FatherB.__init__(self,age)self.gender=genderson=Son('陈梅梅',20,'女')# 调用Son类中的__init__执行
son.showA()
son.showB()
方法重写
class Person:#默认继承了objectdef __init__(self,name,age):self.name=nameself.age=agedef show(self):print(f'大家好,我叫:{self.name},我今年:{self.age}岁')#Student继承Person类
class Student(Person):#编写初始化的方法def __init__(self,name,age,stuno):super().__init__(name,age)# 调用父类的初始化方法self.stuno=stunodef show (self):#调用父类中的方法super().show()print(f'我来自XXX大学,我的学号是:{self.stuno}')#Doctor继承Person类
class Doctor(Person):# 编写初始化方法def __init__(self,name,age,department):super().__init__(name,age)self.department=departmentdef show (self):# super().show()#满用父类中show方法print(f'大家好,我叫:{self.name},我今年{self.age}岁,我的工作科室是:{self.department}')# 创建第一个子类对象
stu=Student('陈梅梅',20,'1001')
stu.show()#调用子类自己的show方法doctor=Doctor('张--', 32,'外科')
doctor.show()#调用子类自己的show()方法
Python中的多态
class Person():def eat(self):print('人,吃五谷杂粮')class Cat():def eat(self):print('猫,喜欢吃鱼')class Dog():def eat(self):print('狗,喜欢啃骨头')#这三个类中都有一个同名的方法,eat
# 编写函数
def fun(obj): # obj是丽数的形式参数,在定义处知道这个形参的数据类型吗obj.eat()# 通过交量obj(对象)调用eat方法# 创建三个类的对象
per=Person()
cat = Cat()
dog = Dog()# 调用fun函数
fun(per)#Python中的多态,不关心对象的数据类型,只关心对象是否具有同名方法
fun(cat)
fun(dog)
object类
class Person(object):def __init__(self,name,age):self.name=nameself.age=agedef show(self):print(f'大家好,我叫:{self.name},我今年:{self.age}岁')#创建Person类的对象
per=Person( '陈梅梅',20)# 创建对象的时候会自动满用__init__方法()
print(dir(per))#自动调用了__str__方法
class Person(object):def __init__(self,name,age):self.name=nameself.age=age# 方法重写def __str__(self):return '这是一个人类,具有name和age两个实例属性' # 返回是一个字符串#创建Person类的对象
per=Person( '陈梅梅',20)
print(per)#还是内存地址吗?不是,--str--方法中的内容 直接输出对象名,实际上是调用__str--方法
print(per.__str__())#手动调用
对象的特殊方法
a=10
b=20
print(dir(a))# Python中一切皆对象
print(a+b)# 执行加法运算
print(a.__add__(b))
print(a.__sub__(b))# 执行减法运算
print(f'{a}<{b}吗?',a.__lt__(b))
print(f'{a}<={b}吗?',a.__le__(b))
print(f'{a}=={b}吗?',a.__eq__(b))
print('-'*40)
print(f'{a}>{b}吗?',a.__gt__(b))
print(f'{a}>={b}吗?',a.__ge__(b))
print(f'{a}!={b}吗?',a.__ne__(b))print('-'*40)
print(a.__mul__(b))#乘法
print(a.__truediv__(b))#除法
print(a.__mod__(b))#取余
print(a.__floordiv__(b))#整除
print(a.__pow__(2))
Python中的特殊属性
class A :passclass B:pass
class C(A,B):def __init__(self,name ,age):self.name=nameself.age=age# 创建类的对象
a=A()
b=B()
#创建C类的对象
c=C( '陈梅梅', 20)
print('对象a的属性字典:',a.__dict__)# 对象的属性字典
print('对象b的属性字典:',b.__dict__)
print('对象c的属性字典:',c.__dict__)print('对象a所属的类:',a.__class__)
print('对象b所属的类:',b.__class__)
print('对象c所属的类:',c.__class__)print('A类的父类:',A.__base__)
print('B类的父类:',B.__base__)
print('C类的父类:',C.__base__)#A类,如果继承了N多个父类,结果只显示第一个父类print('A类的层次结构:',A.__mro__)
print('B类的层次结构:',B.__mro__)
print('C类的层次结构:',C.__mro__)#C类继承了A类,B类,间接继承了object类#于类列表
print('A类的子类列表:',A.__subclasses__())# A的子类有C类
print('B类的子类列表:',B.__subclasses__())
print('C类的子类列表:',C.__subclasses__())#[]列表
类的深拷贝与浅拷贝
class CPU():passclass Disk():passclass Computer():# 计算机由CPU和硬盘def __init__(self,cpu,disk):self.cpu=cpuself.disk=diskcpu=CPU()#创建了一个CPU对象
disk=Disk()# 创建了一个硬盘对象# 创建一个计算机对象
com=Computer(cpu,disk)cpU=CPU()#创建了一个CPU对象
disk=Disk()# 创建了一个硬推对象# 创建一个计算机对象
com=Computer(cpu,disk)
# 变量(对象)的赋值
com1=com
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com1,'子对象的内存地址:',com1.cpu,com1.disk)print('-'*40)
import copy
com2=copy.copy(com)#com2是新产生的对象,com2的子对象,cpu,disk不变
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com2,'子对象的内存地址:',com2.cpu,com2.disk)#类对象的深拷贝
print('-'*40)
com3=copy.deepcopy(com)#com3是新产生的对象,com3的子对象,cpu,disk也会重新创建
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com3,'子对象的内存地址:',com3.cpu,com3.disk)
本章总结
实战
实战1 计算面的面积和周长
class Circle:def __init__(self,r):self.r=r#计算面积的方法def get_area(self):#return 3.14*self.r*self.rreturn 3.14*pow(self.r,2)#计算周长的方法def get_perimeter(self):return 2*3.14*self.r# 创建对象
r=eval(input('请输入圆的半径:'))
c=Circle(r)
# 调用方法
area=c.get_area()# 调用计算面积的方法
perimeter=c.get_perimeter()# 调用计算周长的方法
print('圆的面积为:',area)
print('圆的周长为:',perimeter)
实战2 定义学生类录入5个学生信息存储到列表中
class Student:def __init__(self,name ,age,gender,score):self.name=nameself.age=ageself.gender=genderself.score=score#实例方法def info(self):print(self.name,self.age,self.gender,self.score)print('请输入5位学生信息:(姓名#年龄#性别#成绩)')
lst=[]# 用于存储5个学生对象
for i in range(1,6):s = input(f'请输入第{i}位学生信息及成绩')s_lst = s.split('#')# 索引为0的是姓名,索引为1的是年龄,索引为2的是性别,索引为3的是成绩# 创建学生对象stu = Student(s_lst[0], s_lst[1], s_lst[2], s_lst[3])# 将学生对象添加到列表中lst.append(stu)# 遍历列表,调用学生对象的info方法
for item in lst: # item的数据类型是Student类型item.info()#对象名,方法名()
实战3 使用面向对象思想实现乐器演奏
class Instrument():#父类def make_sound(self):passclass Erhu(Instrument):def make_sound(self):print('二胡在弹奏')class Pinao(Instrument):def make_sound(self):print('钢琴在弹奏')class Violin(Instrument):def make_sound(self):print('小提琴在弹奏')# 编写一个函数
def play(obj):obj.make_sound()# 测试
er = Erhu()
piano = Pinao()
vio = Violin()# 调用方法
play(er)
play(piano)
play(vio)
实战4使用面向对象思想编写出出租车和家用轿车类
class Car(object):def __init__(self,type,no):self.type=typeself.no=nodef start(self):print('我是车,我能启动')def stop(self):print('我是车,我可以停止')#出租车
class Taxi(Car):def __init__(self,type,no,company):super().__init__(type,no)self.company=company#重写父类的启动和停止的方法def start(self):print('乘客您好!')print(f'我是{self.company}出租车公司,我的车牌时:{self.no},您要去哪里?')def stop(self):print('目的地到了,请您扫码付款,欢迎下次乘坐')# 家用轿车
class FamilyCar(Car):def __init__(self,type,no,name):super().__init__(type,no)self.name=namedef start(self):print(f'我是{self.name},我的轿车我做主')def stop(self):print('目的地到了,我们去玩儿吧!')# 测试
taix=Taxi( '上海大众','京A88888','长城')
taix.start()
taix.stop()
print('-'*40)
family_car=FamilyCar( '广汽丰田','京B66666','武大郎')
family_car.start()
family_car.stop()
模块的简介与自定义模块
模块的导入
name='卷狗'def info():print(f'大家好,我是{name}')
name='juan'
age=18
def info():print(f'姓名:{name},年龄:{age}')
import my_info #(1)import
print(my_info.name)
my_info.info()import my_info as a
print(a.name)
a.info()#(2)from ..import
from my_info import name# #导入的是一个具体的变最的名称
print(name)
#info()from my_info import info # 导入的是一个具体的函数的名称
info()#通配符
from my_info import *print(name)
info()# 同时导入多个模块
import math,time,random
from my_info import*
from introduce import *
# 导入模块中具有同名的变量和函数,后导入的会将之前导入的进行覆盖
info()print('------------------------------')
#如果不想覆盖、解决方案,可以使用import
import my_info
import introduce
# 使用模块中的函数或变量时,模块名打点调用
my_info.info()
introduce.info()
Python中的包
def info():print('大家好,我叫ysj,今年18岁')
name='杨淑娟
print('版权:ysjk')
print('讲师:ysj')
import admin.my_admin as a#包名.模块名 admin是包名,my_admin是模块名
a.info()print('-'*40)
from admin import my_admin as b #from 包名import模块 as 别名
b.info()print('-'*40)
from admin.my_admin import info #from 包名.模块名 import 函数/变量等
info()from admin.my_admin import * #from 包名,模块名 import *
print(name)
主程序运行
\
Python中常用的内置模块及random模块中常用的函数
import random
# 设置随机数的种子
random.seed(10)
print(random.random())
print(random.random())print('-'*40)
random.seed(10)
print(random.randint( 1,100))#[1,100]print('-------------------')
for i in range(10):#[m,n)步长为k,m-->start-->1,n->stop->10,k->stepprint(random.randrange(1,10,3))#12行代码执行了10次print('--------------------')
print(random.uniform(1,100))#[a,b]随机小数lst=[i for i in range(1,11)]print(random.choice(lst))#lst是列表,称为序列# 随机的排序
random.shuffle(lst)
print(lst)
time模块中常用的函数
import time
now=time.time()
print(now)obj=time.localtime()#struct time对象
print(obj)obj2=time.localtime(60)#60秒1970年,1月1日,8时,1分,0秒
print(obj2)
print(type(obj2))
print('年份:',obj2.tm_year)
print('月份:',obj2.tm_mon)
print('日期:',obj2.tm_mday)
print('时:',obj2.tm_hour)
print('分:',obj2.tm_min)
print('秒:',obj2.tm_sec)
print('星期:',obj2.tm_wday)#[0,6],3,表示是星期四,2表示的是星期三
print('今年的多少天:',obj2.tm_yday)
print(time.ctime())# 时间戳对应的易读的字符串 Wed 0ct 25 12:13:19 2023#日期时间格式化
print(time.strftime( '%Y-%m-%d',time.localtime()))#str--字符串f->format --time时间
print(time.strftime( '%H:%M:%S',time.localtime()))
print('%8月份的名称:',time.strftime('%B',time.localtime()))
print('%A星期的名称:',time.strftime( '%A',time.localtime()))#字符串转成struct_time
print(time.strptime('2008-08-08','%Y-%m-%d'))
time.sleep(20)
print('helloworld')
datetime模块中datetime类的使用
from datetime import datetime #从datetime模块中 导入datetime类
dt=datetime.now()
print('当前的系统时间为:',dt)
#datetime是一个类,手动创建这个类的对象
dt2=datetime( 2028,8,8,20, 8)
print('dt2的数据类型',type(dt2),'dt2所表示的日期时间:',dt2)
print('年:',dt2.year,'月:',dt2.month,'日:',dt2.day)
print('时:',dt2.hour,'分:',dt2.month,'秒:',dt2.second)#比较两个datetime类型对象的大小
labor_day=datetime( 2028, 5, 1, 0, 0, 0)
national_day=datetime( 2028, 10, 1, 0, 0, 0)
print('2028年5月1日比2028年10月1日早吗?',labor_day<national_day) #True# datetime类型与字符串进行转换
nowdt=datetime.now()
nowdt_str=nowdt.strftime('%Y/%m/%d %H:%M:%S')
print('nowdt的数据类型:',type(nowdt),'nowdt所表示的数据是什么?',nowdt)
print('nowdt_str:',type(nowdt_str),'nowdt_str所表示的数据是什么?',nowdt_str)#字符串类型转成datetime类型
str_datetime='2028年8月8日 20点8分'
dt3=datetime.strptime(str_datetime,'%Y年%m月%d日 %H点%M分')
print('str_datetime的数据类型:',type(str_datetime),'str_datetime所表示的数据:',str_datetime)
print('dt3的数据类型:',type(dt3),'dt3所表示的数据:',dt3)
timedelta类的使用
from datetime import datetime
from datetime import timedelta
#创建两个datetime类型的对象
delta1=datetime( 2028, 10, 1)-datetime( 2028, 5, 1)
print('delta1的数据类型是:',type(delta1),'delta1所表示的数据是:',delta1)
print('2028年5月1日之后的153是:',datetime( 2028, 5, 1)+delta1)#通过传入参数的方式创建一个timedelta对象
td1=timedelta(10)
print('创建一个10天的timedelta对象',td1)
td2=timedelta( 10, 11)
print('创建一个10天11秒的timedelta对象',td2)