1:面向对象基础
1:面向对象的基本概念
1:面向过程,(怎么做)
把完成某一个需求的 所有步骤 从头到尾 逐步实现
根据开发需求,将某些 功能独立的代码 封装 成一个函数
最后完成的代码,就顺序的调用 不同的函数
特点:
注重 步骤与过程
开发复杂的项目,没有固定的套路,开发难度很大
2:面向对象(谁来做)
相比较函数,面向对象是更大封装,根据职责 再一个对象中封装多个方法
1:要完成某一需求前,首先确定一下职责,-----要做的事情
2:根据职责 确定不同的对象,对象内部封装不同的 方法(多个)
3:最后完成代码,就是顺序的让不同的对象 调用不同的方法
特点:
1:注重 对象和职责,不同的对象 承担不同的职责
2:对应 复杂项目的开发,提供固定的套路
3:
2:类和对象的基本概念
类和对象 是面向对象的两个核心概念
1:类:
类是对一群 有相同的特征 或者 的事物的一个统称,是抽象的,不能直接使用
特征:被称为属性
行为:被称为方法
类是负责创建对象的
2:对象
对象:是由类创建出来具体存在的,可直接使用的
有哪一个类创建的对象,就拥有哪一类中定义的:
属性
方法
3:类和对象的关系
类是模板,对象是根据类这个模板创建出来的 ,现有类,再有对象
类只有一个,而对象可以多个
类中定义什么 属性和方法,对象就有什么对象和方法,不可能多,也不可能少
3:设计类的三要素和名词提炼法
1:在程序开发中,要设计一个类,满足一下三个要素
1):类名:这类事物的名字,满足大驼峰命名法
2):属性:这类事物有什么杨的特征
3):方法:这类事物有什么样的行为
大驼峰命名法:
1):每一个单词的首字母大写
2:): 单词和单词之间没有下划线
2:类名的确定
名词提炼法:分析整个业务流程,出现名词,就是要找的类
3:属性和方法的确定
对 对象的特征描述, 通常可以定义成属性
对象具体有的行为(动词),通常可以定成方法
4:内置的dir函数查询对象的方法列表
变量,数据,函数,都会对象
在python中使用两种方法验证
1:在标识符数据 后输入一个 . 然后tab ,ipython会提示调用的方法列表
2:使用内置函数,dir 传入 标识符/数据,可以查看对象内的所有属性和方法
5:定义简单的类01_基本语法
1:python中定义只包含方法的类
class类名:def方法1(self,参数列表):pass
def方法2(self,参数列表):pass
第一个参数必须是self ,类名的命名规则符合大驼峰命名法
2:当一个类定义完成之后,要使用这个类创建对象
对象的变量名=类名()
6:定义简单的类02_案例演练
1:第一个面向对象的程序
需求:小猫爱吃鱼,小猫要喝水
分析:定义一个 猫类,定义两个方法eat和drink ,按需求,不需要定义属性
classCat:defeat(self):print("小猫爱吃鱼")defdrink(self,):print("小猫要喝水")#创建对象
tom =Cat()
tom.eat()
tom.drink()
7:定义简单的类03_接受对象变量的同时是对对象的引用
classCat:defeat(self):print("小猫爱吃鱼")defdrink(self,):print("小猫要喝水")#创建对象
tom =Cat()"""tom变量记录的是对象在内存中的地址,
也就是Tom 变量应用新建毛的对象
利用print函数输出Tom变量,是能够输出这个变量应用的对象 是有一个类创建的对象,以及内存中的地址"""tom.eat()
tom.drink()print(tom)#<__main__.Cat object at 0x0000025595BECD30>
8:定义简单的类_04 创建多个猫对象
classCat:defeat(self):print("小猫爱吃鱼")defdrink(self,):print("小猫要喝水")#创建对象
tom =Cat()"""tom变量记录的是对象在内存中的地址,
也就是Tom 变量应用新建毛的对象
利用print函数输出Tom变量,是能够输出这个变量应用的对象 是有一个类创建的对象,以及内存中的地址"""tom.eat()
tom.drink()print(tom)#<__main__.Cat object at 0x0000025595BECD30>#创建多个猫对象,他们不是一个猫对象
lazy_cat=Cat()
lazy_cat.drink()
lazy_cat.eat()print(lazy_cat)#<__main__.Cat object at 0x00000249FF46CE48>
9:-self-01 在类的外部给对象添加属性
1:给类的对象设置属性,非常容易,但不推荐使用
#创建对象
tom =Cat()
tom.name="Tom"#创建多个猫对象,他们不是一个猫对象
lazy_cat=Cat()
lazy_cat.name="大懒猫"
10:self-02 利用self在类的封装的方法中输出多个属性
classCat:#有哪一个对象调用的方法,方法内的 self 就是哪一个对象的引用
defeat(self):print("%s爱吃鱼" %self.name)defdrink(self,):print("%s要喝水"%self.name)#创建对象
tom =Cat()
tom.name="Tom"tom.eat()
tom.drink()#创建多个猫对象,他们不是一个猫对象
lazy_cat=Cat()
lazy_cat.name="大懒猫"lazy_cat.drink()
lazy_cat.eat()
11:初始化方法-01-在类的外部给对象添加属性的隐患
先调用方法,在设置属性
classCat:defeat(self):print("%s爱吃鱼" %self.name)defdrink(self,):print("%s要喝水"%self.name)#创建对象
tom =Cat()
tom.eat()
tom.drink()
tom.name="Tom"
报错
AttributeError: 'Cat' object has no attribute 'name'
提示:对象包含哪些属性,应该封装在类的内部
12:初始化方法-02-创建对象时自动调用初始化方法
当用类名创建对象时,会自动执行以下操作
1:为对象在内存中分配空间——创建对象
2:为对象的属性 设置初始值——初始化方法(init)
这个初始化方法就是_init_方法,是对象的内置方法,专门定义一个类 具有哪些属性方法!
classCat:def __init__(self):print("这是一个初始化方法")
tom=Cat()#使用类名创建对象的时候,会自动调用初始化方法_init_
这是一个初始化方法
13:初始化方法-03-初始化方法中定义属性
在_init_方法内部使用 self.属性名=属性的初始值 ,就可以定义属性
定义属性之后,在使用Cat创建对象,都会有该属性
classCat:def __init__(self):print("这是一个初始化方法")
self.name="tom"
defeat(self):print("%s爱吃鱼" %self.name)
tom=Cat()
tom.eat()
print(tom.name)#打印Tom的属性
14初始化方法-04-使用参数设置属性的初始值
在开发的过程中,如果希望 创建对象的同时,就设置对象的属性,可以对init方法进行改造
1:把希望设置的属性值,定义成_init_ 方法参数
2:在方法内部使用 self.属性=形参 接受外界传递的参数
3:在创建对象时,使用 类名(属性1,属性2……)调用
classCat:def __init__(self,new_name):print("这是一个初始化方法")#self.name="tom"
self.name=new_namedefeat(self):print("%s爱吃鱼" %self.name)
tom=Cat("tom")
tom.eat()
lazy_cat=Cat("大懒猫")
lazy_cat.eat()
15:-内置方法-01- del的方法和对象的生命周期
当一个对象从内存中销毁前,会自动调用_del_方法
classCat:def __init__(self,new_name):
self.name=new_nameprint("%s 来了"%self.name)def __del__(self):print("%s去了" %self.name)#tom是一个全局变量
tom=Cat("tom")print("-" *50)
tom 来了
--------------------------------------------------
tom去了
classCat:def __init__(self,new_name):
self.name=new_nameprint("%s 来了"%self.name)def __del__(self):print("%s去了" %self.name)#tom是一个全局变量
tom=Cat("tom")#del 关键字可以删除一个对象
deltomprint("-" *50)
tom 来了
tom去了
--------------------------------------------------
16:内置方法-02- str- 方法定制变量的输出信息
在python中使用print输出对象变量,默认情况下,会输出这个变量 引用的对象 是 有哪一个类创建的,以及内存中的地址
在开发中,希望使用 print 输出 对象变量时,能够打印自定义的内容,就可以使用_str_内置方法了
注意:_str_方法必须返回一个字符串
classCat:def __init__(self,new_name):
self.name=new_nameprint("%s 来了"%self.name)def __del__(self):print("%s去了" %self.name)def __str__(self):return "我是一只小猫【%s】"%self.name#tom是一个全局变量
tom=Cat("tom")print(tom)#del 关键字可以删除一个对象
deltomprint("-" *50)
tom 来了
我是一只小猫【tom】
tom去了
--------------------------------------------------
2:面向对象练习
1:小明爱跑步
1):封装
封装面向对象的一大特点,
面向对象的第一步--将属性和方法 封装到一个抽象的类中
外界使用类创建对象,然后让对象去调用方法
对象方法的细节都被封装在类的内部
2):小明爱跑步
1:小明的体重 75.0 公斤
2:小明每次跑步会减肥 0.5公斤
3:小明每次吃东西 增加 1 公斤
classPerson:def __init__(self,name,weight):
self.name=name
self.weight=weightdef __str__(self):return "我是%s,我的体重是%.2f 公斤"%(self.name,self.weight)defeat(self):print("%s是吃货,吃完东西在减肥"%self.name)
self.weight+=1.0
defrun(self):
self.weight-=0.5xiaoming=Person("xiaoming",75.0)
xiaoming.eat()
xiaoming.run()print(xiaoming)
3):提示:在对象的内部,是可以直接访问对象的属性的
同一个类中的 多个对象之间,属性互不干扰
classPerson:def __init__(self,name,weight):
self.name=name
self.weight=weightdef __str__(self):return "我是%s,我的体重是%.2f 公斤"%(self.name,self.weight)defeat(self):print("%s是吃货,吃完东西在减肥"%self.name)
self.weight+=1.0
defrun(self):
self.weight-=0.5xiaoming=Person("xiaoming",75.0)
xiaoming.eat()
xiaoming.run()print(xiaoming)
xiaomei=Person("xiaomei",55.0)
xiaomei.run()
xiaomei.eat()print(xiaomei)
2:摆放家具
需求
1:房子(house)有户型,总面积 和家具名称列表
新房子没有任何的家具
2:家具(HOuseItem)有名字 和占地面积,其中
席梦思(bed):4平米
衣柜(chest):2平米
餐桌(table):1.5平米
4:打印房子时,要求输出:户型,总面积,剩余面积,家具名称列表
HouseItem
naem
area
_init_(self,name,are)
_str_(self)
House
house_type
area
free_area
item_list
_init_(self,house_type,are)
_str_(self)
add_item(self,item)
剩余面积
创建房子对象时,定义一个剩余面积的属性,初始值和总面积相等
当调用 add_item 方法时,向房间添加家具时 剩余面积-=家具面积
家具类
classHouseItem:def __init__(self,name,area):
self.name=name
self.area=areadef __str__(self):return ("[%s]:\t%.2f 平米"%(self.name,self.area))
bed=HouseItem("席梦思",4)
chest=HouseItem("衣柜",2)
table=HouseItem("餐桌",1.5)print(bed)print(chest)print(table)
房子类
classHouse:def __init__(self,house_type,area):
self.house_type=house_type
self.area=area#剩余面积
self.free_area=area#家具名臣列表
self.item_list=[]def __str__(self):#python 能够自动将一对括号的代码连接在一起
return ("户型:%s \n总面积:%.2f[剩余面积:%.2f]\n家具:%s"
%(self.house_type,self.area,
self.free_area,self.item_list ))defadd_item(self,item):print("要添加%s"%item)#self.item_list.append(item)
my_house=House("两室一厅",60)print(my_house)
小结:让房子类调用三次 add_item,准备添加家具
添加家具
classHouseItem:def __init__(self,name,area):
self.name=name
self.area=areadef __str__(self):return ("[%s:]%.2f 平米"%(self.name,self.area))classHouse:def __init__(self,house_type,area):
self.house_type=house_type
self.area=area#剩余面积
self.free_area=area#家具名臣列表
self.item_list=[]def __str__(self):#python 能够自动将一对括号的代码连接在一起
return ("户型:%s \n总面积:%.2f[剩余面积:%.2f]\n家具:%s"
%(self.house_type,self.area,
self.free_area,self.item_list ))defadd_item(self,item):print("要添加%s"%item)#判断家具面积
if item.area>self.free_area:print("%s面积太大了,无法添加"%(item.name))return
#将加剧名臣添加到列表
self.item_list.append(item.name)#计算剩余面积
self.free_area-=item.area
bed=HouseItem("席梦思",4)
chest=HouseItem("衣柜",2)
table=HouseItem("餐桌",1.5)
创建房子对象
my_house=House("两室一厅",60)
my_house.add_item(bed)
my_house.add_item(chest)
my_house.add_item(table)print(my_house)
3:封装案例
1):封装
封装封装面向对象的一大特点,
面向对象的第一步--将属性和方法 封装到一个抽象的类中
外界使用类创建对象,然后让对象去调用属性方法
对象方法的细节都被封装在类的内部
一个对象的 属性 是另一个类创建的 对象
01:士兵突击
需求:
1:士兵 许三多 有一把 AK47
2:士兵可以开火
3:抢能够发射子弹
4:抢装填子弹--增加子弹数量
分析:
类1: 士兵; 属性:名字,抢。 方法:开火
类2: 强; 属性:名字,子弹 方法:发射子弹
写抢类:
classGun:def __init__(self,model):#定义抢的型号
self.model=model#抢子弹的数量
self.bullet_count =0defadd_bullet(self,count):
self.bullet_count+=countdefshoot(self):pass
#判断子弹是否有子弹
if self.bullet_count<=0:print("[%s] 没有子弹...."%self.model)#发射子弹 -1
self.bullet_count-=1
#提示发射
print("[%s] 突突突...[%d]"%(self.model,self.bullet_count))
ak47=Gun("ak47")
ak47.add_bullet(50)
ak47.shoot()
写士兵类
classGun:def __init__(self,model):#定义抢的型号
self.model=model#抢子弹的数量
self.bullet_count =0defadd_bullet(self,count):
self.bullet_count+=countdefshoot(self):pass
#判断子弹是否有子弹
if self.bullet_count<=0:print("[%s] 没有子弹...."%self.model)#发射子弹 -1
self.bullet_count-=1
#提示发射
print("[%s] 突突突...[%d]"%(self.model,self.bullet_count))classSoldier:def __init__(self,name):#姓名
self.name=name#假设每一个士兵开始都没有抢
self.gun=Nonedeffire(self):#判断是否有抢
if self.gun isNone:print("[%s] 还没有抢...."%self.name)return
#高喊口号
print("冲啊...[%s]"%self.name)#让强装填子弹
self.gun.add_bullet(50)#发射子弹
self.gun.shoot()#1:创建抢的对象
ak47=Gun("ak47")#2:给抢装子弹#ak47.add_bullet(50)#3:发射#ak47.shoot()#1:创建士兵的对象
xusanduo=Soldier("许三多")#2:给许三多给一把枪(赋值的形式)一个对象的 属性 是另一个类创建的 对象
xusanduo.gun=ak47#3;开枪
xusanduo.fire()#print(ak47)
身份运算符
身份运算符用于比较 内存的地址 是否一致--是否是对同一对象的引用
在python 中针对None 比较时,建议用 is 判断
is 与 == 区别
is 是判断两个变量 引用的对象是否是同一个
== 用于判断 应用的变量的值是否是同一个
4:私有属性和方法
1:应用场景及定义方式
实际开发中, 对象 的某些属性或方法 可能希望 在对象的内部使用, 而不希望在外部访问到
2:定义方式
在定义属性和方法时 ,在属性或方法的名前 增加 两个下划线 定义的就是私有属性 或方法
classWomen:def __init__(self,name):
self.name=name
self.__age=18
def __secret(self):#在对象的内部可以直接访问对象的私有属性
print("%s 的年龄是 %d"%(self.name,self.__age))
xiaomei=Women("小美")#私有属性,在外界不能直接访问
#print(xiaomei.__age)
xiaomei.__secret
3:伪私有属性和方法
在前面加上 _类名
#print(xiaomei.__age)
xiaomei._Women__secret
3:单继承和方法的重写
面向对象的三大特性
1:封装: 根据职责 将属性和方法 封装到一个抽象的类中
2:继承:是代码的重用
3:多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
单继承
概念:子类拥有父类的所有方法和属性
语法:
class类名(父类名):pass
子类继承父类,可以直接享受父类中以封装好的方法,不需要再次开发
子类 根据职责, 封装子类特有的 属性和方法
专业的术语:
父类===基类
子类===派生类
继承的传递性:
子类拥有 父类 以及 父类的父类 中的所有属性和方法
方法的重写
应用场景:当父类方法的实现 满足不了子类的需求,可以对方法进行 重写
重写 父类的方法 的两种情况
覆盖父类的方法
对父类方法进行扩展
1:覆盖父类的方法(父类方法的实现和子类完全不同)
classAnimal:defeat(self):print("吃....")defdrink(self):print("喝....")defrun(self):print("跑...")classDog(Animal):defbark(self):print("汪汪叫...")classXioaTianQuan(Dog):deffly(self):print("还会飞...")defbark(self):print("叫的跟神一样")
xtq=XioaTianQuan()#如果子类中重写了父类的方法#子类调用对象时,会调用子类中重写的方法
xtq.bark()
2:对父类方法进行扩展(父类的方法是子类的一部分)
采用 super(). 的形式,调用父类方法的执行
关于super()
python 中super是一个特殊的类
super()是super创建的
使用场景, 重写父类方法时,调用父类中封装的方法
classAnimal:defeat(self):print("吃....")defdrink(self):print("喝....")defrun(self):print("跑...")classDog(Animal):defbark(self):print("汪汪叫...")classXioaTianQuan(Dog):deffly(self):print("还会飞...")defbark(self):#针对子类的需求编写代码
print("叫的跟神一样")#使用super(). 调用父类中封装的方法
super().bark()#编写其他代码
xtq=XioaTianQuan()
xtq.bark()
4:私有方法和属性
classA:def __init__(self):
self.num1=100self.__num2=200
def __test(self):print("私有方法 %d %d"%(self.num1,self.__num2))classB(A):passb=B()print(b)#在外界不能直接访问对象的私有属性调用对象的私有方法
print(b.__num2)#AttributeError: 'B' object has no attribute '__num2'
b._teat()
1:子类对象 不能直接 在自己的方法内部,直接访问 父类的私有属性 或私有 方法
classA:def __init__(self):
self.num1=100self.__num2=200
deftest(self):print("父类的公有方法 %d"%self.__num2)classB(A):defdemo(self):#在子类的对象方法中,不能直接访问父类的私有属性
print("访问父类的私有属性 %d" % self.__num2)#在子类的对象方法中,不能直接访问父类的私有方法
self.__test()
b=B()print(b)#在外界不能直接访问对象的私有属性调用对象的私有方法
print(b.__num2)#AttributeError: 'B' object has no attribute '__num2'
b._teat()
2:子类对象 可以通过父类的 共有方法 间接访问 私有属性或私有方法
classA:def __init__(self):
self.num1=100self.__num2=200
deftest(self):print("父类的公有方法 %d"%self.__num2)
self.__test()def __test(self):print("私有方法 %d %d"%(self.num1,self.__num2))classB(A):defdemo(self):#在子类的对象方法中,通过直接访问父类的公有属性来访问类的私有属性
print("访问父类的私有属性 %d" %self.num1)#在子类的对象方法中,通过直接访问父类的公有方法来访问父类的私有方法
self.test()
b=B()print(b)
b.demo()
5: 多继承
概念
子类 可以拥有 多个父类,并且具有 所有父类的属性和方法
语法
class子类名(父类1,父类2):pass
注意事项
如果父类间存在同名的属性和方法,应该尽量避免
python中的MRO,主要用于多继承时 判断方法,属性的调用路劲
print(C._mrc_)
python 3.0 中所有类的基类是object
6:多态
面向对象的三大特性
1:封装: 根据职责 将属性和方法 封装到一个抽象的类中
2:继承:是代码的重用
3:多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
增加代码的灵活度
以继承和重写父类方法为前提
是调用方法的技巧,不会影响内部的设计
多态案列演练
需求
1:在dog类中封装game方法(普通狗简繁玩耍)
2:定义 xiaotianquan继承 dog 并重写 game 方法(哮天犬上天完)
3:定义person类, 并且封装一个和狗完的方法
方法内部直接让 狗对象调用 game 方法
classDog:def __init__(self,name):
self.name=namedefgame(self):print("%s 蹦蹦跳跳的玩耍..."%self.name)classXiaoTianQuan(Dog):defgame(self):print("%s 飞上天..."%self.name)classProson:def __init__(self,name):
self.name=namedefgame_with_dog(self,dog):print("%s 和 %s 快乐的玩耍..."%(self.name,dog.name))#让狗玩耍
dog.game()#创建狗对象
wangcai=Dog("旺财")#创建一个小明对象
xiaoming =Proson("小明")#让小明调用和狗完的方法
xiaoming.game_with_dog(wangcai)
案例小结:
person类中只需让狗对象,调用game方法,而不关心具体是什么狗
在程序执行时,传入不同的狗对象实参,就会产生不同的结果
7:类属性,类方法,静态方法
1.1术语——实例
1:现象对象开发中,第一步,设计类
2:使用类名创建对象,创建对象的动作有两部:
在内存中分配对象
调用初始化方法 __init__为对象初始化
3:对象创建之后,内存中就有一对象实实在在的存在,-----实例
因此:通常把
创建出来的对象就做类的实例
创建对象的动作叫做实例化
对象的属性叫做实例属性
对象的方法叫做实例方法
在程序执行时:
对象各自拥有自己的实例属性
调用对象的方法,可以通过self.的方式访问自己的属性和自己的方法
结论:
每一个对象都有自己独立的内训空间,保存个不同的属性
多个对象的方法,在内存只有一份,在调用方法时需要把对象引用 传递到方法内部
1.2:类属性
1:类是一个特殊的对象
python中一切皆对象
class A: 属于类对象
a=A() 属于实例对象
在程序运行时,类同样会被加载到内存中
在python中,类是一个特殊的对象,--类对象
在程序运行时,类对象在内存中只有一份,使用一个类可以创建出很多的类实例
除了封装实例的属性和方法外,类对象还可以创建拥有自己的属性和方法
类属性和类方法
通过类名.的方式,可以方法类属性和类方法
2:概念和使用
类属性 就是给 类对象中 定义的 属性
通常会记录与这个类相关的特性
类属性不会记录 具体对象的特征
在class 关键字下方,利用赋值语句来定义
实例需求
定义一个工具类
每件工具都有自己的名字name
需求 --知道这个类创建了多少个工具对象
classTools:#使用赋值语句定义类属性,记录所有工具的数量
count=0def __init__(self,name):
self.name=name#让属性值加1
Tools.count+=1
#创建工具对象
tool1=Tools("斧头")
tool2=Tools("榔头")#输出工具对象的总数
print(Tools.count)
3:属性的获取机制——向上的查找机制
访问属性的两种方式
类名.类属性
对象.类属性(不推荐)
注意:
如果使用对象.类属性=值 ,只会给对象添加一个属性,而不会影响到类属性的值
classTools:#使用赋值语句定义类属性,记录所有工具的数量
count=0def __init__(self,name):
self.name=name#让属性值加1
Tools.count+=1
#创建工具对象
tool1=Tools("斧头")
tool2=Tools("榔头")
tool3=Tools("水桶")#给雷属性进行赋值
tool3.count=99
print(tool3.count)#输出工具对象的总数
print(Tools.count)
1.3:类方法
类方法是针对类对象定义的方法
在类方法内部,可以直接访问类属性,或者调用替他方法
语法如下;
@classmethoddef类方法名(cls):pass
通过类名. 调用类方法调用类方法时,不需要传递cls 参数
在方法内部:
可以通过 cls. 访问类的属性
也可以通过 cls. 调用替他类方法
实例需求
定义一个工具类
每件工具都有自己的名字name
需求 --再类中封装一个 show_tools_count 的类方法,输出使用当前这个类创建的的对象个数
classTools:#使用赋值语句定义类属性,记录所有工具的数量
count=0def __init__(self,name):
self.name=name#让属性值加1
Tools.count+=1@classmethoddefshow_tool_count(cls):#在类方法的内部,可以通过cls.的方式访问类属性
print(Tools.count)#创建工具对象
tool1=Tools("斧头")
tool2=Tools("榔头")
tool3=Tools("水桶")#调用类方法
Tools.show_tool_count()
1.4:静态方法
开发场景:既不需要访问实例属性或调用实例方法,也不需要访问类属性或者调用类方法
@staticmethoddef静态方法名():pass
通过 类名. 的方式来调用
classDog:
@staticmethoddefrun():print("小狗会跑")
Dog.run()
1.5:方法综合案例分析
需求
1:设计一个 game 类
2:属性
定义一个类属性top_score 记录游戏的最高分
定义一个实例属性 play_name 记录当前玩家姓名
3:方法:
静态方法show_help 显示游戏的帮助信息
类方法 show_top_score 显示历史最高分
实例方法 start_game 开始当前的玩家游戏
4:程序步骤
查看帮助信息
查看历史最高分
创建游戏对象
classGame:#类属性:历史最高分
top_score=0#实例属性
def __init__(self,play_name):
self.play_name=play_name
@staticmethoddefshow_help():print("帮助信息:让僵尸进入大门")
@classmethoddefshow_top_score(cls):print(Game.top_score)defstart_game(self):print("开始游戏了 %s"%self.play_name)#查看帮助信息
Game.show_help()#查看历史最高分
Game.show_top_score()#创建游戏对象
game=Game("小明")
game.start_game()
案例小结:
1:实例方法
2:类方法
3:静态方法
8:单例模式
01:单例设计模式
目的:
让类创建对象,在系统中只有唯一的一个实例
每一次执行 类名(),返回的对象,内存地址是相同的
02:__new__方法
1:使用类名()创建对象时,python解释器 首先会 调用__new__方法,分配内存空间
2;__new__是一个object 基类提供的 内置静态方法,主要作用有两个:
在内存中为对象 分配空间
返回对象的引用
3:python解释器获得对象的引用后,将引用作为第一个参数,传递给__init__ f方法
重写 __new__ 方法非常固定
重写__new__方法一定要 return super().__new__(cls)
否则python解释器 得不到 分配空间的对象引用,就不会 调 用对象的初始化方法,就会返回一个 None
注意:__new__是一个静态方法,在调用时 需要传递cls参数
classMusicPlay:def __new__(cls, *args, **kwargs):#创建对象时,new方法会自动调用
print("创建对象,分配空间")#为对象分配空间
instance =super().__new__(cls)#返回对象引用
returninstance
play=MusicPlay()print(play)
03:python中的单例
单例:让类创建的对象,在系统中只有唯一的一个实例
定义一个类属性,初始值NOne,用于记录单例对象的引用
重写new方法
如果 类属性 is None ,调用父类,分配空间,,并在类属性中记录结果
回 类属性 中记录的对象引用
classMusicPlay:#记录一个被创建的对象引用‘
instance=Nonedef __new__(cls, *args, **kwargs):#判断类属性属性是否是空对象
if cls.instance isNone:#调用父类方法,为第一个对象分配空间
cls.instance=super().__new__(cls)#返回类属性对象保存的对象引用
returncls.instance
play1=MusicPlay()print(play1)
play2=MusicPlay()print(play2)
只执行一次初始化工作
使用类名()创建对象时,python解释器自动两个方法
__new__ 分配空间
__init__对象初始化
需求:只执行一次初始化方法
classMusicPlay:#记录一个被创建的对象引用‘
instance=None#记录是否执行初始化工作
init_flag=Falsedef __new__(cls, *args, **kwargs):#判断类属性属性是否是空对象
if cls.instance isNone:#调用父类方法,为第一个对象分配空间
cls.instance=super().__new__(cls)#返回类属性对象保存的对象引用
returncls.instancedef __init__(self):#判断是否执行初始化工作
ifMusicPlay.init_flag:return
#如果没有执行过,在此执行初始化动作
print("初始化播放器")#修改类属性的标记
MusicPlay.init_flag=True
play1=MusicPlay()print(play1)
play2=MusicPlay()print(play2)
9: 异常
01:异常的概念
程序运行时,如果PYthon解释器 遇到一个错误,会停止程序的执行,并且提示一些错误的信息,这既是异常
程序停止执行,并且提示错误信息,这个动作,我们称为抛出异常
程序开发时,不可能将所有的特殊情况处理的面面俱到,通过异常捕获可以针对突发事件做处理,从而保证程序的稳定性和健壮性
02:捕获异常
简单的捕获语法
try:
尝试执行代码except:
出现错误的处理
案例:要求用户输入整数
try:
num=int(input("请输入一个整数:"))except:print("请输入正确的整数")print("-" *50)
03:错误类型的捕获
在程序执行时,可能会遇到不同类型的异常,并且需要针对不同类型的异常,做出不同的相应,就需要捕获错误类型
当python 解释器 抛出异常时,最后一行错误信息的第一个单词你是错误类型
案例-要求用户输入整数
需求:
1:提示用户输入一个整数
2;使用 8 除以输入的整数 并且输出
try:
num=int(input("请输入一个正数:"))
result=8 /numprint(result)exceptZeroDivisionError:print("除数不能为0")exceptValueError:print("你输入的是非法的数字,请重新输入")
04:捕获位置错误
在程序开发时,要预测到所有可能的错误,还是有一定的难度的
如果希望程序无论出现任何错误,都可以抛出
try:
num=int(input("请输入一个正数:"))
result=8 /numprint(result)exceptZeroDivisionError:print("除数不能为0")exceptException as a : #把错误交给变量a,最后输出print("未知错误 %s" % a)
05:异常捕获的完整语法
else : 只有在没有异常的时候才执行的代码
finally: 无论是否有异常,都会执行的代码
try:
num=int(input("请输入一个正数:"))
result=8 /numprint(result)exceptZeroDivisionError:print("除数不能为0")exceptException as a :print("未知错误 %s" %a)else:print("尝试成功")finally:print("无论是否出现错误都会执行的代码")print("-" * 50)
06:异常的传递性
被调用的函数会把异常传给调用方,最后会交给主控程序处理,因此,在主控程序处理异常即可;
defdemo():return int(input("请输入一个整数:"))defdemo2():returndemo()#利用异常的传递性,在主程序铺货异常
try:print(demo2())exceptException as a:print("未知错误:%s"%a)
07;抛出raise 异常
应用场景:
在开发中,除了代码执行出错以外,还可以根据应用程序 特有的业务需求, 主动抛出异常
示例:
提示用户输入密码,如果长度小于8, 抛出异常
抛出异常:
python中提供了一个 Exception 异常类
在开发时,满足特定的业务需求,希望抛出异常类
创建Exception 的对象
使用raise 关键字抛出异常
definput_passwd():#提示用户输入信息
num=input("请输入密码:")#判断密码长度是否>=8,是,返回密码
if len(num)>=8:returnnum#<8,主动抛出异常
print("主动抛出异常")#1)创建异常对象
ex=Exception("密码长度不够")#2)主动抛出异常
raiseextry:print(input_passwd())exceptException as a :print(a)
10:模块和包
01:模块
1.1 模块的概念
模块是python架构的一个核心概念
每一个扩展名 .py 结尾的python源文件都是一个模块
模块名 同样是一个标识符,需要符合标识符的命名规则
在模块定义的全局变量 ,函数,类 都是提供给外界可用的工具
模块好比 工具包,想要使用这个工具包中的工具,就必须先导入这个模块
1.2:模块导入的两种方法
1)import 模块
在导入模块时,每个导入应该独占一行
import模块1import 模块2
通过调用就可用里面的工具
importxpq_01importxpq_02
xpq_01.say_hello()
xpq_02.say_hello()
dog=xpq_01.Dog()print(dog)
cat=xpq_02.Cat()print(cat)
使用as指定模块的别名
importxpq_01 as DogModulimportxpq_02 as CatMOdul
DogModul.say_hello()
CatMOdul.say_hello()
dog=DogModul.Dog()print(dog)
cat=CatMOdul.Cat()print(cat)
2):from......import
从某一个工具中,导入部分工具。
from 模块名 import 工具名
导入之后,可以直接使用 模块的工具---全局变量,函数,类
注意:如果两个模块,存才同名的函数,那么 后倒入的模块,会覆盖先导入的模块
开发时,import 代码 应该统一写在代码的顶部,一旦发现冲突,可以使用as 关键字 给其中的一个工具起一个别名
1.3 模块的搜索顺序
搜索当前目录 模块名文件,如果有,就直接导入,如果没有,就搜索系统目录
模块有一个内置的属性,__file__可以查看模块的完整路径
importxpq_01 as DogModulimportxpq_02 as CatMOdulprint(DogModul.__file__)#D:\PycharmProjects\模块\xpq_01.py
DogModul.say_hello()
CatMOdul.say_hello()
dog=DogModul.Dog()print(dog)
cat=CatMOdul.Cat()print(cat)
1.4:原则--每一个文件都应是可以被导入的
导入文件时,文件中没有任何缩进的代码,都会被执行一遍
实际开发场景
开发人员通常会在 模块下方 增加一些测试代码,仅在模块内使用,仅在模块内使用,而在其他文件中不需要执行
__name__属性
__name__属性可以做到, 测试模块的代码 只在测试的模块中运行,而在被导入时不会被执行
__name__是python中的一个内置属性,记录这一个字符串,
如果是被其他文件导入的,__name__就是模块名
如果是当前执行的程序 __name__是__main__
__name__模块
defsay_hello():print("你好你好,我是 say_hello")#如果直接执行模块,__main__
if __name__=="__main__":print (__name__)#文件被导入时,能够被执行的代码不被执行
print ("小明开发的模块")
say_hello()
__name__导入模块
import __name__模块
print ("-" *50)
很多python文件中看到以下格式代码
#导入模块#定义变量‘’#定义类#定义函数#在代码的最下方
defmain()#。。。
pass
#根据__name__判断,是否执行下方代码
if __name__=="__main__":
main()
02:包
概念:
包是一个包含多个模块的 特殊目录
目录下有一个特殊文件__init__
包名的命名方式和变量一致
好处
使用import 包名 可以一次性的导入包中的所有模块
哟使用 包 中的模块,需要 __init__.py 中指定 对外界提供中的模块列表
#从当权目录 导入 模块列表
from . importsend_messagefrom . import receive_message
11:文件操作
12:文本编码
13:内建函数eval
14:反射
#反射 : 是用字符串类型的名字 去操作 变量#反射是对象中的属性和方法 # hasattr getattr setattr delattr
classA:deffunc(self):print('in func')
a=A()
a.name='alex'a.age=63
#反射的对象属性
ret=getattr(a,'name')#a 对象名, ‘name’属性名
print(ret )#alex#反射方法属性
a.func()
ret= getattr(a,'func')
ret()
反射类的属性和方法
classA:
price= 20@classmethoddeffunc(cls):print('in func')#反射类的属性
A.priceprint(getattr(A,'price'))#20
## 反射类的方法 :classmethod staticmethod
A.func()if hasattr(A,'func'):
getattr(A,'func')#in func
模块中的属性和方法
#模块#import my#反射模块的属性#print(my.day)#print(getattr(my,'day'))
#反射模块的方法#getattr(my,'wahaha')()
#内置模块也能用#time#asctime
importtimeprint(getattr(time,'time')())print(getattr(time,'asctime')())
importsysprint(sys.modules['__main__'])## 反射自己模块中的变量#print(getattr(sys.modules['__main__'],'year'))#
## 反射自己模块中的函数
getattr(sys.modules['__main__'],'qqxing')()
变量名= input('>>>')print(getattr(sys.modules[__name__],变量名))#要反射的函数有参数怎么办?#print(time.strftime('%Y-%m-%d %H:%M:S'))#print(getattr(time,'strftime')('%Y-%m-%d %H:%M:S'))
#一个模块中的类能不能反射得到#import my#print(getattr(my,'C')())#if hasattr(my,'name'):#getattr(my,'name')