1、
class GirlFriend(object):
#定义女朋友类:
eyes = 2
#类属性(静态属性),是属于当前类的
#当前类的所有对象,所共有的特征
sex = "女"
"""
说明
"""
#初始化方法
def __init__(self,name,age,height,weight):
#实例属性
self.name = "qwe"
self.age = age
self.height = height
self.weight = weight
#函数属性
def xiyifu(self):
#定义洗衣服功能:
print(self.name,"洗衣服")
def chuitu(self):
#定义捶腿功能:
print("捶腿")
def tiwolianji(self):
#定义替我联机功能:
print("打怪升级")
2、
#调用类属性,需要使用类名去调用(对象名也可以调用,但是不建议)
# print(GirlFriend.name)
3、
#类名不能调用实例属性,也不要去调用实例方法
print(GirlFriend.eyes)
4、
#可以在对象创建时,就让他拥有不同的属性值
girl_1 = GirlFriend("迪丽热巴",18,170,170)
#通过对象调用类属性,没问题
#但是不能修改
print(girl_1.eyes)
5、
#如果通过对象去修改类属性,会创建一个新的实例属性,这个实例属性在对象中会覆盖掉类属性
girl_1.eyes = 3
GirlFriend.eyes = 3
print("girl1的",girl_1.eyes)
6、
#实例属性的增加
girl_1.money = 100
7、
#实例属性的删除
del girl_1.name
8、
#实例属性的修改
girl_1.age = 19
9、
#实例属性的查看
print(girl_1.age)
10、
#修改某个对象的实例属性,对当前类的其他对象,没有任何影响
#如果,在类中做了修改,所有对象都会发生改变
girl_1.chuitu()
girl_1.tiwolianji()
# girl_1.name = "迪丽热巴"
#在类的外部,给对象添加属性
# girl_1.money = 100
# print(girl_1.money)
girl_2 = GirlFriend("baby",35,120,250)
print(girl_2.name)
print("girl2的",girl_2.eyes)
11、
#定义天使:
#光圈,翅膀,有眼睛,有腿等等,漂亮,善良,会飞,有法力,能打坏人,能救人,治疗
#类是一个模板(里面放了一些属性和方法)
#对象(也叫当前类的一个实例),是通过类创建出来的,用来完成具体工作
12、
#设计程序的思路:
#首先,根据需求,来设计类,这个过程被称为"抽象",从真实存在的事务当中,抽象出共同的属性和方法
13、
# #类名,大家约定俗成,首字母大写
# class Person:
# def __init__(self):
# #放属性
# self.name = "小明"
# self.age = 18
# #方法和属性,只关心完成当前工作所需要的
# def eat(self):
# #具体的工作(算法)
# print("人可以吃东西")
# #self:哪个对象调用了当前方法,self就代表谁
# def run(self):
# print(self.name)
# print("人会跑")
#
# #创建对象(实例化)
# 小明 = Person()
# 小明.run()
# print(小明.name,小明.age)
14、
# class Hero:
# def __init__(self,name,HP,MP,ATK):
# self.name = name
# self.hp = HP
# self.mp = MP
# self.atk = ATK
# def jineng1(self):
# print("电光毒龙钻")
# self.hp -= 20
#
# def jineng2(self):
# print("摸鸡头下蛋")
#
# alex = Hero("alex",100,200,250)
# bigB = Hero("元宝",200,50,300)
# alex.at = 123123123
# del alex.jineng1
# alex.jineng1()
# if alex.hp <= 0:
# del alex
# alex.atk = 20
# print(alex.name)
15、
# 创建一个英雄类:
# • 包含英雄的各项属性:例如血量魔法值等等(注意哪些应该是类属性,哪些应该作
# 为实例属性)
# • 英雄有自残的能力,自残后会掉血
# class Hero:
# def __init__(self,hp):
# self.hp = hp #血量
# self.mp = 200 #魔法值
# def zican(self):
# print("我钻我自己")
#自身数量值减1
# self.hp -= 1
16、
# • 创建一个狗类:
# • 包含名字,颜色,品种,年龄,性别等属性
# • 有一个自我介绍的方法,打印自身的属性信息(我叫XXX。。。)
# • 狗有看家的能力,狗有叫的能力,在看家方法中调用叫的方法
# class Dog:
#定义狗类:
# def __init__(self,name,color,type,age,sex):
#实例化姓名、颜色、品种、年龄、性别
# pass
# def ziwojieshao(self):
# print("我叫",self.name,)
# def kanjia(self):
#类里面的方法相互调用:
# self.jiao()
# def jiao(self):
# print("汪~汪~")
# douding = Dog()
# douding.kanjia()
17、
num = 0
class Hero:
num = 0
def __init__(self):
self.name = "abc"
Hero.num += 1 #数量自加1
def run(self):
print("会跑")
for i in range(10):
"循环调用10圈"
alex = Hero()
bigB = Hero()
a = Hero()
print(Hero.num)
18、
## 面向过程(函数式编程)
通过数学逻辑去解决问题(设计算法,得到想要的结果)
函数式编程:提高了代码的复用性,提高了维护性
## 面向对象
python中 万物皆对象
面向过程,的程序,执行效率高
面向对象,的开发效率高
类:一类具有相同特征的事物的总称
对象:通过类,创建的一个具体事务,用来完成工作
基础数据结构(列表,元组...)是数据的封装,函数是算法的封装
类:是抽象出来的,数据和算法都能封装,可维护性更高,能处理更复杂的问题,代码逻辑更清晰
创建类和对象的格式
过程描述:
1,抽象
2,通过抽象出的内容来设计类
3,class 类名:
属性
def __init__(self):
self.XXX = XXX
方法
函数定义一样
4,创建对象:
对象名 = 类名()
5,调用对象的属性和方法使用万能的点.
创建对象时:
1,在内存中开辟一块空间
2,自动调用init方法
python27day18面向对象--------------------------------------------------------------------------------------------
1、
#方法和函数究竟有什么区别
class Person:
def abc(self):
pass
a = Person()
print(type(a.abc))
print(type(Person.abc))
#通过对象去调用时,是方法
#其他情况,比方说通过类名调用,或者放在类外的时候叫函数
2、
#例一:
class Baooy:
def __init__(self,name,girlFriend = None):
self.name = name
self.girlFriend = girlFriend
def eat(self):
if self.girlFriend:
print(f"{self.name}带着他的女朋友{self.girlFriend}去吃饭")
else:
print("单身狗,吃狗粮")
def movie(self):
if self.girlFriend: #加self确认的
print(f"{self.name}带着他的女朋友{self.girlFriend}去看电影") #打印时一定加上self
else:
print("单身狗,回家看")
a = Baooy("zs","zs1")
a.eat() #对象调用函数属性:
a.movie()
3、
# class Person:
# def __init__(self,name,age):
# self.name = name
# self.hp = 100
# def play(self,tool):
# print(self.name,"钻",tool.name)
# tool.hp -= 20
# print(tool.name,"还有",tool.hp,"点血")
# def kanjia(self,tool):
# tool.kanjia()
# class Dog:
# def __init__(self,name,hp):
# self.name = name
# self.hp = hp
# def kanjia(self):
# print("汪~汪~~")
#
# alex = Person("Alex",83)
# bigB = Person("宝元",76)
# alex.play(bigB)
# xiaohei = Dog("小黑",20)
# bigB.kanjia(xiaohei)
4、
#关联关系就是在一个类的方法当中,引入了另一个对象(另一个类的对象)
# 定义一个英雄类和一个反派类
# • 两个类都包含名字、血量,攻击力(ATK),和一个技能(skill)
# • 两派对象互殴
# • 血量为0死亡,删除对象(del 对象名)
import random
class Hero:
def __init__(self,name,hp,atk):
self.name = name
self.hp = hp
self.atk = atk
def skill(self,tool): #tool = alex
print(self.name,"对",tool.name,"使出了波动拳") #name = 宝元,tool = alex
tool.hp -= self.atk * random.randint(1,5)/2
class Boss:
def __init__(self,name,hp,atk): #name = alex
self.name = name
self.hp = hp
self.atk = atk
def skill(self,tool):
print(self.name,"对",tool.name,"使出了独孤九剑") #name = alex、tool = bigB、tool.name = bigB.name = 宝元
tool.hp -= self.atk * random.randint(1,5)/2
bigB = Hero("宝元",200,15)
alex = Boss("alex",150,20)
while True:
bigB.skill(alex)
alex.skill(bigB)
if bigB.hp <= 0:
print("游戏结束")
del bigB #删除Hero的实例
break
if alex.hp <= 0:
print("游戏结束")
del alex #删除Boss的实例
break
结果: 宝元 对 alex 使出了波动拳
alex 对 宝元 使出了独孤九剑
宝元 对 alex 使出了波动拳
alex 对 宝元 使出了独孤九剑
宝元 对 alex 使出了波动拳
alex 对 宝元 使出了独孤九剑
宝元 对 alex 使出了波动拳
alex 对 宝元 使出了独孤九剑
宝元 对 alex 使出了波动拳
alex 对 宝元 使出了独孤九剑
游戏结束
5、
# class Father(object):
# #在py3中,如果一个类,没有显式的继承任何一个类,那么他默认继承object
# # def __init__(self,name,age):
# # self.name = name
# # self.age = age
# def livelikeyemen(self):
# print("打妈妈")
# class Son:
# def __init__(self,f):
# self.f = f
# def abc(self):
# self.f.livelikeyemen()
# #父类方法重写
# def livelikeyemen(self):
# print("打妹妹")
# daming = Father()
# xiaoming = Son(daming)
# xiaoming.abc()
6、
# class Anm(object):
# """定义动物类"""
# def __init__(self,name,age):
# """实例化姓名和年龄"""
# self.name = name
# self.age = age
# def run(self):
# """定义跑的方法"""
# print("123")
# class Dog(Anm):
# """定义狗类继承动物类"""
# #如果子类也有自己的初始化方法,可能会出错
# #解决方式,在子类的init方法里面,调用父类的init方法用super()
# def __init__(self,name,age):
# self.xihuanshi = True
# super().__init__(name,age)
# def jump(self):
# print("跳")
# def run(self):
# print("abc")
# """调用动物类的跑方法"""
# Anm.run(self)
# """运行动物类的跑方法"""
# super().run()
# class Cat(Dog):
# """定义猫类继承狗类"""
# def __init__(self):
# """调用狗类里面的init方法用super()"""
# super().__init__()
# def jiao(self):
# print("喵喵~~~")
# a = Dog("动物",20)
# a.run()
7、
class 蛇:
def __init__(self):
self.ya = 2
def panta(self):
print("pan")
def run(self):
print("123")
class 蜘蛛:
def __init__(self):
eyes = 8
jiao = 8
def 吐丝(self):
print("cici")
def run(self):
print("456")
class 人(蜘蛛,蛇):
pass
# def __init__(self, name,age):
# self.name = name
# self.age = age
# super().__init__()
xiaoming = 人()
xiaoming.run()
8、
# 类之间的关系
## 依赖关系:执行某个动作的时候,需要其他类的对象来帮助你完成这个动作
就是将一个类的对象或者类名放到另一个类的方法当中就叫依赖
此时,类之间的关系是最轻的,因为随时可以更换其他对象
9、
class Person:
def play(self,tools):
tools.run()
print("我要打游戏了")
class Compture:
def run(self):
print("电脑已经打开,DNF已登录")
class Phone:
def run(self):
print("王者荣耀已经登陆")
xiaoMing = Person()
xmPhone = Phone()
hwCom = Compture()
xiaoMing.play(xmPhone) #一个类的对象或者类名放到另一个类的方法当中
xiaoMing.play(hwCom) #一个类的对象或者类名放到另一个类的方法当中
结果: 王者荣耀已经登陆
我要打游戏了
电脑已经打开,DNF已登录
我要打游戏了
10、
## 组合关系:将一个类的对象,放到另一个类的属性中(作为一个组成部分)
一对一关系
一对多关系
一对一关系:
class Baooy:
def __init__(self,name,girlFriend = None):
self.name = name
self.girlFriend = girlFriend
def eat(self):
if self.girlFriend:
print(f"{self.name}带着他的女朋友{self.girlFriend.name}去吃饭")
else:
print("单身狗,吃狗粮")
def movie(self):
if self.girlFriend:
print(f"{self.name}带着他的女朋友{self.girlFriend.name}去看电影")
else:
print("单身狗不配看电影")
class Girl:
def __init__(self,name):
self.name = name
bao = Baooy("宝哥")
friend = Girl("唐艺昕")
bao.eat()
bao.movie()
bao.girlFriend = friend
bao.eat()
bao.movie()
结果: 单身狗,吃狗粮
单身狗不配看电影
宝哥带着他的女朋友唐艺昕去吃饭
宝哥带着他的女朋友唐艺昕去看电影
11、
## 继承关系:在不改变现有类的情况下,扩展这个类,子类可以获得父类的所有属性和方法
通过继承创建的新类称为"子类"或"派生类",被继承的类称为"基类"、"父类"或"超类"
在python中,同时支持单继承与多继承
增加了类的耦合性(耦合性不宜多,宜精)
减少了重复代码
使得代码更加规范化,合理化
单继承:子类可以继承父类的属性和方法,修改父类,所有的子类都会受影响。
python有两个判断继承的函数
isinstance()用于检查实例类型:isinstance(对象,类型)
issubclass()用于检查类继承:issubclass(子类,父类)
继承的格式:
class 子类名(父类名):
子类可以定义自己的方法,也可以定义和父类同名的方法(方法重写),这时,子类方法会覆盖掉父类的同名方法、
super()关键字在当前类中调用父类方法
super()关键字:
·子类如果编写了自己的构造方法,但没有显式调用父类的构造方法,而父类构造函数初始化了一些属性,就会出现问题
·如果子类和父类都有构造函数,子类其实是重写了父类的构造函数,如果不显式调用父类构造函数,父类的构造函数就不会被执行
·解决方式:调用超类构造方法,或者使用super函数super(当前类名,self).__init__()
因此,如果子类和父类都拥有自己的初始化方法,需要在子类的初始化方法中调用父类的init方法
多重继承:包含多个间接父类
多继承
·有多个直接父类
·大部分面向对象的编程语言(除了C++)都只支持单继承,而不支持多继承
·多继承不仅增加了编程的复杂度,而且很容易导致一些莫名的错误
·Python虽然在语法上明确支持多继承,但通常推荐如果不是很有必要,则尽量不要使用多继承,而是使用单继承
·这样可以保证编程思路更清晰,而且可以避免很多麻烦
·如果多个直接父类中包含了同名的方法
·此时排在前面的父类中的方法会“遮蔽”排在后面的父类中的同名方法
class YeYe:
def __init__(self):
print("初始化爷爷")
class Qinba(YeYe):
def __init__(self):
print("进入亲爸类")
YeYe.__init__(self)
print("初始化亲爸")
class GanDie(YeYe):
def __init__(self):
print("进入干爹类")
YeYe.__init__(self)
print("初始化干爹")
class ErZi(Qinba,GanDie):
def __init__(self):
Qinba.__init__(self)
GanDie.__init__(self)
print("初始化儿子")
bigB = ErZi()
结果: 进入亲爸类
初始化爷爷
初始化亲爸
进入干爹类
初始化爷爷
初始化干爹
初始化儿子
12、
调用方式为
```
父类名.__init__(self)
```
如果只是想操作另一个类的对象,用依赖
如果两个类当中存在has a 的关系,用组合
如果是is a 的关系,用继承(尽量少用继承,多用组合)
13、
新式类:继承了object的类,就叫新式类
经典类:没有继承object的类
py3中,所有的类都是新式类
py2中,如果没有显式继承,那么这个类就没有集成任何类,所以有经典类,也有新式类
# class Boy:
# def __init__(self,name,tools = None):
# self.name = name
# self.girl = tools
# def play(self):
# if self.girl:
# print(self.name,"玩",self.girl.name)
# else:
# print("单身狗玩自己吧")
#
# class Girl:
# def __init__(self,name):
# self.name = name
# class Hero:
# def __init__(self,wuqi,hujia):
# self.wuqi = wuqi
# self.hujia = hujia
# def skill(self,tool):
# print(f"用{self.wuqi.name}打{tool.name}")
#组合关系:将一个类的对象,作为另一类的属性
#一对多关系
class Person:
def __init__(self):
self.girl = []
def bamei(self,g1):
self.girl.append(g1)
def play(self):
for i in self.girl:
print(i.name,end=" ")
i.play()
class Girl:
def __init__(self,name,age):
self.name = name
self.age = age
def play(self):
print("陪玩")
girl1 = Girl("小丽",18)
girl2 = Girl("贾玲",30)
girl3 = Girl("韩红",50)
bigB = Person()
bigB.bamei(girl3)
bigB.bamei(girl1)
bigB.play()
结果: 韩红 陪玩
小丽 陪玩
class Boy:
def __init__(self):
self.girl_list = []
def baMei(self,girl):
self.girl_list.append(girl)
def happy(self):
for i in self.girl_list:
i.play()
class Girl:
def __init__(self,name):
self.name = name
def play(self):
print(f"{self.name}和你一起玩")
bao = Boy()
friend1 = Girl("唐艺昕")
friend2 = Girl("迪丽热巴")
friend3 = Girl("杨颖")
bao.baMei(friend1)
bao.baMei(friend2)
bao.baMei(friend3)
bao.happy()
结果: 唐艺昕和你一起玩
迪丽热巴和你一起玩
杨颖和你一起玩
14、
# 定义一个用户类,用户名和密码是这个类的属性,实例化两个用户,分别有不同的用户名和密码
# 登陆成功之后才创建用户对象
# 设计一个方法 修改密码
# class User:
# def __init__(self,name,pw):
# self.name = name
# self.pw = pw
# def rPassW(self):
# newPW = input("请输入新密码")
# self.pw = newPW
# num = 0
# while True:
# userName = input("请输入用户名")
# userPW = input("请输入密码")
# if userName == "alex" and userPW == "123123":
# xiaoming = User("xiaoming","123abc")
# xiaoli = User("xiaoli","123456")
# break
# else:
# print("输入有误!,请重新输入!")
# num += 1
15、
# 定义一个列表的操作类:Listinfo
# 包括的方法:
# 1 列表元素添加: add_key(keyname) [keyname:字符串或者整数类型]
# 2 列表元素取值:get_key(num) [num:整数类型]
# 3 列表合并:update_list(list) [list:列表类型]
# 4 删除并且返回最后一个元素:del_key()
# list_info = Listinfo([44,222,111,333,454,'sss','333'])
# class ListInfo:
# def __init__(self, lis):
# self.lis = lis
# def add_Key(self, keyname):
# self.lis.append(keyname)
# def get_key(self,num):
# return self.lis[num]
# def update_list(self, new_list):
# self.lis + new_list
# def del_key(self):
# return self.lis.pop()
15、
# class A:
# Country = ['中国'] # 静态变量/静态属性 存储在类的命名空间里的
# def __init__(self,name,age,country): # 绑定方法 存储在类的命名空间里的
# self.name = name
# self.age = age
# def func1(self):
# print(self)
# a = A('alex',83,'印度')
# b = A('wusir',74,'泰国')
# a.Country[0] = '日本'
# print(a.Country)
# print(b.Country)
# print(A.Country)
结果: ['日本']
['日本']
['日本']
python27day20面向对象--------------------------------------------------------------------------------------------
封装”就是将抽象得到的数据和行为相结合,形成一个有机的整体
·元组,列表,字典等等:数据的封装,通过引用去使用数据
·函数:算法的封装
·没有函数,功能靠每一行代码去直接执行·耦合度太高,复用性太差,开发效率太低
封装的目的是简化编程和增强安全性
·使用者不必关心该类具体的实现细节
·通过接口(万能的点)
·还可以给予的特定的访问权限来使用类的成员
·明确区分内外:
·类的实现者可以修改内部封装的东西而不影响外部调用者
·外部调用者只需要知道自己可以使用该类对象的哪些功能
私有属性,私有方法
·“双下划线”开始的是私有成员,在类外部不可以直接用属性或方法名调用,子类中也不能访问到这个数据
·可以提供外界访问的接口
·将不需要对外提供的内容都隐藏起来
·把属性都隐藏,提供公共方法对其访问
·双下滑线开头的属性在继承给子类时,子类是无法覆盖的
class Abc:
def __init__(self):
self.__name = "abc"
def __set(self,x):
self.__name = x
def get_name(self):
print(self.__name)
a = Abc()
print(a.__name) #直接访问找不到
结果:AttributeError: 'Abc' object has no attribute '__name' (AttributeError:“Abc”对象没有属性“u name”)
a.get_name() #通过类里面的函数属性可以找到
结果:abc
破解私有属性和私有方法:
·在名称前加上_类名,即_类名__名称
·其实加双下划线仅仅是一种变形操作
·类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式
class Abc:
def __init__(self):
self.__name = "abc"
def __set(self):
print("111")
def get_name(self):
print(self.__name)
a = Abc()
a._Abc__set()
结果:111
多态体现1:python是一种多态语言,不关心对象的类型
·对于弱类型的语言来说,变量并没有声明类型,因此同一个变量完全可
以在不同的时间引用不同的对象
·毫无疑问,在python中对象是一块内存,内存中除了包含属性、方法之
外,还包含了对象类型,我们通过引用来访问对象,比如a=A(),首先
python创建一个对象A,然后声明一个变量a,再将变量a与对象A联系起
来。变量a是没有类型的,它的类型取决于其关联的对象
class Bird:
def move(self,field):
print("鸟在%s上自由地飞翔" %field)
class Dog:
def move(self,field):
print("狗在%s里飞快的奔跑" %field)
x = Bird()
x.move("天空")
x = Dog()
x.move("草地")
结果: 鸟在天空上自由地飞翔
狗在草地里飞快的奔跑
同一个变量x:在执行同一个move()方法时,由于x指向的对象不同,因此呈现
出不同的行为特征,这就是多态。
多态体现2:一类事物有多种形态(polymorphic)
·一个抽象类有多个子类,但方法实现不同
·例如:动物类有多个子类,每个子类都重新实现了父类的某个方法,但
方法的实现不同(休息的方法)
·此时需要有继承,需要有方法重写
栈Stack和队列Queue实现put和get方法:
class Stack:
def __init__(self):
self.lis = []
def put(self,num):
self.lis.append(num)
def get(self):
if self.lis != []:
return self.lis.pop()
class Queue:
def __init__(self):
self.lis = []
def put(self,num):
self.lis.append(num)
def get(self):
if self.lis != []:
return self.lis.pop(0)
# 数据结构:数据在内存中的存放顺序
栈/队列
栈:FILO--3,2,1
队列:FIFO--1,2,3
l = []
l.put(1)
l.put(2)
l.put(3)
l.get()
l.get()
l.get()
多态:
体现一:python中一个引用,可以指向不同类型的对象
体现二:一类事物,有多种形态
多态性:
在继承和方法重写的基础上,定义一个统一的接口,不关心传入对象的类型,只关心实现了哪些方法
python崇尚鸭子类型
·不关心类型,不需要继承,只关注方法实现,这种情况被称为鸭子类型
·“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子
·在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的
总结:Python本身就是支持多态性的
·增加了程序的灵活性(通用性),以不变应万变,不论对象千变万化,使用者都是同一种形式去调用
·增加了程序的可扩展性,通过继承某个类创建了一个新的类,接口使用者无需更改自己的代码,还是用原方法调用
对比:
·多态强调的是:一类事物不同的形态
·多态性强调的是:同一操作,作用对象不同,表现出不同实现方式(只关心行为结果)
class Car:
def __init__(self,color):
self.color = color
def run(self):
print(self.color,"小汽车在跑")
class Cat:
def __init__(self,name):
self.name = name
def run(self):
print("猫咪",self.name,"在跑")
a = Car("红色")
a.run()
结果:红色 小汽车在跑
b = Cat("白色")
b.run()
结果:猫咪 白色 在跑
有时通过单一对象方便集中管理资源
·单例模式是保证一个类仅有一个实例的设计模式
·保证了在程序的不同位置都可以且仅可以取到同一个对象实例:如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。
设计模式:处理特定问题,可重用解决方案
创建单例模式:
class Danli:
ins = None
def __new__(cls, *args, **kwargs):
if cls.ins == None:
cls.ins = object.__new__(cls)
return cls.ins
def __init__(self):
pass
class Boy(Danli):
pass
class Girl(Danli):
pass
xiaoming = Danli()
print(id(xiaoming))
结果:35486800
xiaoHong = Danli()
print(id(xiaoHong))
结果:35486800
工厂模式是不直接暴露对象创建细节,而是通过一个共用类创建对象的设计模式,需要4步:创建基类-创建子类-创建工厂类-使用工厂模式
class Girl:
pass
class Boy:
pass
class Dog:
pass
class Cat:
pass
class Alex:
pass
class Gongchang:
def re_Per(self,arg):
if arg == "G":
return Girl()
elif arg == "B":
return Boy()
print("没有")
约束:指的是对类的约束
在一些重要的逻辑,与用户数据相关等核心部分,要建立一种约束,避免发生此类错误
类的约束有两种解决方式:
方式一:在父类建立一种约束(通过抛出异常)
提取⽗类,在⽗类中定义好⽅法,在这个⽅法中抛⼀个异常。这样所有的⼦类都必须重写这个⽅法.
否则. 访问的时候就会报错
方式二:引入抽象类的概念
举例:
公司让小明给他们的网站完善一个支付功能,小明写了两个类,QQ支付和支付宝支付
但是上面这样写不太放方便,也不合理,老大说让他整改,统一一下付款的方式,小明开始加班整理,使用归一化设计
后来小明接了大项目,公司招了一个新的程序员春哥接替小明的工作,老大给春哥安排了任务,
让他写一个微信支付的功能,春哥随意给微信支付类中的付钱方法起了一个方法名
后来接手这个项目的程序员,也可能随意起名
class Payment:
def pay(self,money):
raise Exception("子类必须实现pay方法")
class QQpay(Payment):
def pay(self,money):
print(f"使用QQ支付{money}")
class Alipay(Payment):
def pay(self,money):
print(f"使用Ali支付{money}")
class Wechat(Payment):
def zhifu(self,money):
print(f"使用微信支付{money}")
def pay(obj,money): #obj = Wechat() #归一化设计:
obj.pay(money) #obj = Wechat()
obj1 = QQpay()
obj2 = Alipay()
obj3 = Wechat()
pay(obj3,300)
结果:Exception: 子类必须实现pay方法
pay(obj2,200)
结果:使用Ali支付200
解决方式二:
用抽象类(制定一种规范)的概念,建立一种约束
基类如下设置,子类如果没有定义父类里面的方法,在实例化对象时就会报错
from abc import ABCMeta,abstractmethod
class Abc123(metaclass=ABCMeta): #设置元类是metaclass是ABCMeta
@abstractmethod
def abc(self):
pass
@abstractmethod
def dfg(self):
pass
class Qwer123(Abc123): #子类继承父类、父类里面的所有属性和方法子类里面必须有:
def abc(self):
print("123")
def dfg(self):
print("345")
a = Qwer123()
# 设置一个类的metaclass(元类)是ABCMeta
# 那么这个类就变成了一个抽象类(接口类)
# 这个类的功能就是建立一个规范
# 由于该⽅案来源是java和c#. 所以不常用
解决方式二:
详解:
Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。ABC是Abstract Base Class(抽象父类)的缩写
abc.ABCMeta是用来生成抽象基础类的元类。由它生成的类可以被直接继承,但是抽象类不能直接创建对象(只能被继承)
@abstractmethod表明抽象方法,如果子类不具备@abstractmethod的方法,那么就会抛出异常
类方法:
指一个类中通过@classmethod修饰的方法
第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)
调用:实例对象和类对象都可以调用
类方法是将类本身作为对象进行操作的方法
使用场景分析:
假设我有一个学生类和一个班级类,想要实现的功能为:
执行班级人数增加的操作、获得班级的总人数
学生类继承自班级类,每实例化一个学生,班级人数都能增加
最后,我想定义一些学生,获得班级中的总人数
因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的
同时,想要获得班级总人数,如果生成一个班级的实例也是没有必要的
版一:
class Class:
pass
class Student(Class):
__num = 0
def __init__(self,name):
self.name = name
Student.set_num()
@classmethod
def get_num(cls):
return cls.__num
@classmethod
def set_num(cls):
cls.__num += 1
s = Student("qwe")
print(Student.get_num())
结果:1
版二:
class Student:
__num = 0
def __init__(self,name,age):
self.name = name
self.age = age
Student.addNum()
@classmethod
def addNum(cls):
cls.__num += 1
@classmethod
def getNum(cls):
return cls.__num
a = Student("qwe",11)
print(Student.getNum())
结果:1
实例方法:对象调用,类名不建议调用
实例属性:对象调用,类名不能调用
类方法:通过类名去调用,对象也可以调用(尽量别)
类属性:通过类名调用,对象也可以调用(尽量别)
self,cls只能在类内使用,在类外无效
静态方法:
使用@staticmethod修饰的方法
参数随意,没有“self”和“cls”参数,方法体中不能使用类或实例的任何属性和方法
实例对象和类对象都可以调用
详解:静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,
但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。
可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数
import time
class TimeTest(object):
def __init__(self,hour,minute,second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod
def showTime():
return time.strftime("%H:%M:%S", time.localtime())
print(TimeTest.showTime())
结果:17:45:20
t = TimeTest(2,10,10)
nowTime = t.showTime()
print(nowTime)
结果:17:45:20
上页中使用了静态方法(函数),然而方法体中并没使用(也不能使用)类或实例的属性(或方法)
若要获得当前时间的字符串时,并不需要实例化对象,此时对于静态方法而言,所在类更像是一种名称空间
其实,我们也可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难
property:是一种特殊的属性,访问它时会执行一段功能(方法)然后返回值
举例:
BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
shang:65kg÷(1.82×1.82)=19.623233908948194
class People:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height**2)
p1 = People("egon",75,1.85)
print(p1.bmi)
结果:21.913805697589478
为什么要用property:
将一个类的方法定义成属性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的
这种特性的使用方式**遵循了统一访问的原则**
属性一般具有三种访问方式,获取、修改、删除
我们可以根据这几个属性的访问特点,分别将三个方法定义为对同一个属性的获取、修改、删除
只有在属性定义property后才能定义setter,deleter
class Person:
def __init__(self,age):
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self,num):
self.__age = num
xiaoli = Person(100)
print(xiaoli.age)
结果:100
xiaoli.age = 120
print(xiaoli.age)
结果:120
property(get_AAA,set_AAA,delete_AAA)
#内置property三个参数与get,set,delete一一对应
class Student(object):
def __init__(self,name,score):
self.name = name
self.__score = score
def get_score(self):
return self.__score
def set_score(self,score):
if 100 > score > 0:
raise ValueError("invalid score")
self.__score = score
s = Student("Bob",59)
print(s.name)
结果:Bob
s.set_score(60)
print(s._Student__score)
结果:ValueError: invalid score
s.set_score(101)
print(s._Student__score)
结果:101
只有@property定义只读,加上@setter定义可读可写,加上@deleter定义可读可写可删除
class Student(object):
def __init__(self,name,score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self,score):
if 100 > score > 0:
print("数据有误!")
self.__score = score
@score.deleter
def score(self):
if 200 > score > 100:
del self.__score
s = Student("Bob",59)
print(s.name)
结果: 数据有误!
Bob
print(s.score)
结果:59
s1 = Student("Bob1",201)
print(s1.score)
结果:201
del s1.score
print(s1.score)
结果:201
s1 = Student("Bob1",101)
print(s1.score)
结果:101
del s1.score
print(s1.score)
结果:AttributeError: 'Student' object has no attribute '_Student__score'
结果:AttributeError: 'Student' object has no attribute '_Student__score'--AttributeError:“Student”对象没有“Student”score属性
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
有四个可以实现自省的函数:hasattr,getattr,setattr,delattr
应用于对象的反射:
class Girl:
num = 0
def __init__(self):
self.name = "Alex"
def run(self):
print("人会跑")
xiaohong = Girl()
print(hasattr(xiaohong,"name"))
结果:True
print(getattr(xiaohong,"run"))
结果:<bound method Girl.run of <__main__.Girl object at 0x0000000002717DA0>>
print(getattr(xiaohong,"name1","没有"))
结果:没有
setattr(xiaohong,"name","宝元")
print(getattr(xiaohong,"name"))
结果:宝元
setattr(xiaohong,"run","宝元")
print(getattr(xiaohong,"run"))
结果:宝元
综合用法:
getattr(obj, "age", setattr(obj, "age", "18"))
应用于类的反射:
class Foo(object):
staticField = "old boy"
def __init__(self):
self.name = "wupeiqi"
def func(self):
return "func"
@staticmethod
def bar():
return "bar"
print(getattr(Foo,"staticField"))
结果:old boy
print(getattr(Foo,"func"))
结果:<function Foo.func at 0x00000000027288C8>
print(getattr(Foo,"bar"))
结果:<function Foo.bar at 0x0000000002728AE8>
应用于当前模块的反射:
每当程序员导入新的模块,sys.modules(是一个字典)都将记录这些模块
import sys
def s1():
print("s1")
def s2():
print("s2")
this_module = sys.modules[__name__]
print(hasattr(this_module,"s1"))
结果:True
a = getattr(this_module,"s2")
a()
结果:s2
反射的应用举例:
当我们打开浏览器,访问一个网站,单击登录就跳转到登录界面,单击注册就跳转到注册界面
但是,你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理
class User:
def login(self):
print("欢迎来到登录页面")
def register(self):
print("欢迎来到注册页面")
def save(self):
print("欢迎来到存储页面")
没学反射之前的解决方式:
while True:
choose = input(">>>").strip()
if choose == "login":
obj = User()
obj.login()
elif choose == "register":
obj = User()
obj.register()
elif choose == "save":
obj = User()
obj.save()
学了反射之后的解决方式:
user = User()
while True:
choose = input(">>>").strip()
if hasattr(user,choose):
func = getattr(user,choose)
func()
else:
print("输入错误")
内置方法:
Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围
__new__(cls[, ...])
__new__ 是在一个对象实例化的时候所调用的第一个方法
__init__(self[, ...])
构造器,当一个实例被创建的时候调用的初始化方法
__del__(self)
析构器,当一个实例被销毁的时候调用的方法(建议不要重写)
__len__
通过len(obj)调用,返回值必须设置为int类型
__hash__ 通过hash(obj)调用(一种消息摘要算法)
hash() 用于获取取一个对象(非可变数据类型)的哈希值
__str__
打印对象时调用
__eq__
比较两个对象
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
异常(Exception)是一个事件,该事件可能会在程序执行过程中发生,影响了程序的正常执行
raise语句显式的抛出异常
Python解释器自己检测到异常并引发它
一般情况下,在Python无法正常处理程序时就会发生异常
异常是Python对象,表示一个错误
当Python程序发生异常时我们需要捕获处理它,否则程序会终止执行
常见异常:
SyntaxError语法错误
IndentationError多打一个空格
NameError 使用一个还未被赋予对象的变量
TypeError 传入对象类型与要求的不符合 (int + str)
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndexError 下标索引超出序列边界
KeyError 试图访问字典里不存在的键
处理异常
程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)
如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃
异常处理的方式1
num1=input('>>: ') #输入一个字符串试试
if num1.isdigit():
int(num1) #我们的正统程序放到了这里,其余的都属于异常处理范畴
elif num1.isspace():
print('输入的是空格,就执行我这里的逻辑')
elif len(num1) == 0:
print('输入的是空,就执行我这里的逻辑')
else:
print('其他情情况,执行我这里的逻辑')
num = int(input("请输入:"))
for i in range(10):
try:
num = 5 / num
except ZeroDivisionError:
print("除数不能为0")
except TypeError:
print("类型错误")
except KeyError:
print("不存在的键")
print(i)
异常处理,可以捕获异常对象,然后作相应处理,让程序继续执行
如果代码没出现异常,程序正常执行
如果出现了是常,except 会尝试捕获,如果捕获成功,执行except下面的内容
for和else的组合:
for i in range(10):
print(i)
else:
print(234)
while和else的组合:
while True:
print(1)
break
else:
print(234)
try:
被检测的代码块
except 异常类型:
try中一旦检测到异常,就执行这个位置的逻辑
如果你不想在异常发生时结束你的程序,只需在try里捕获它
首先,执行 try 子句 (在 try 和 except 关键字之间的部分)
如果没有异常发生,except 子句在 try 语句执行完毕后就被忽略了
如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略
如果异常匹配于 except 关键字后面指定的异常类型,就执行对应的 except 子句。
然后继续执行 try 语句之后的代码
万能异常:
except ... as ...
使用exception as e:查看异常,以及是否按要求捕获到
try:
print(1/0)
raise FileNotFoundError
except Exception as e: #万能异常
print(e)
多分支+万能异常
发生的异常中,有一些异常是需要不同的逻辑处理的,剩下的异常统一处理掉即可
dic = {1: login,2: register,3: dariy,4: article,5: comment,}
print('''欢迎访问博客园系统:
1,登录
2,注册
3,访问日记页面
4,访问文章页面
5,访问评论页面''')
try:
choice = int(input('请输入:'))
dic[choice]()
except ValueError:
print('请输入数字....')
except KeyError:
print('您输入的选项超出范围...')
except Exception as e:
print(e)
try...except...else组合:
与循环中的else类似,try代码中,只要出现了异常,则不会执行else语句,如果不出现异常,则执行else语句
伪代码:
try:
print('扣第一个人钱')
print('给第二个人加钱')
except ValueError:
print('必须输入数字。。。')
else:
print('转账成功')
try...excet...finally组合:
finally:最后一定要执行的语句块
try:
dic = {'name': 'shang'}
print(dic[1])
except KeyError:
print('出现了keyError错误....')
finally:
print('正常执行')
finally应用场景:
1. 关闭文件的链接链接,数据等链接时,需要用到finally
f = open('file',encoding='utf-8')
try:
'''各种操作'''
print(f.read())
'''但是发生错误了, 此时没关闭文件句柄,所以'''
finally:
f.close()
函数中,finally也会在return之前先执行
def func():
try:
return 1
finally:
print('finally')
func()
循环中
while 1:
try:
break
finally:
print('finally')
总结:finally一般是做收尾工作
在一些重要环节出错之前必须一定要做的比如关闭链接的问题时,最好是用上finally作为最后一道防线,收尾。
断言
表示一种强硬的态度,只要assert后面的代码不成立,直接报错,下面的代码就不让你执行
assert 条件
代码
代码
....... (类似if)
自定义异常:
python中提供的错误类型可能并不能解决所有错误
如果以后你在工作中,出现了某种异常无法用已知的错误类型捕获(万能异常只能捕获python中存在的异常),
那么你就可以尝试自定义异常,只要继承BaseException类即可
自定义异常:
class HelloError(Exception): #自定义异常类HelloError
def __init__(self,n):
self.n=n
try:
n=input("请输入数字:")
if not n.isdigit():
raise HelloError(n)
except HelloError as hi:
print("HelloError:请输入字符。
您输入的是:",hi.n)
else:
print("未发生异常")