一、类、对象的概念
类: 一组具有相同或相似特征(属性)和行为(方法)的一系列(多个)对象的集合 【1:类名 2:类的属性[一组数据;在类的内部定义的变量] 3:类的方法[允许操作的方法(行为)] 】
对象: 类的实例化,类是对象的抽象化 (个人理解:“类”与C中的结构体相似,“对象”则是以结构体定义的变量)
1.1、创建一个类
#改进 __init__ 可通过参数 传递实例属性
import time #导入时间函数
class Labixiaoxin:
name='小新' #在方法外部定义的变量称之为 类属性
age=5
def __init__(self,dogname,job,love): # __init__ 在创建对象是由编译器自动执行
self.dogname=dogname #定义在方法内部且使用self定义的的数据称之为 实例属性
self.job=job
self.love=love
pass
def eat(self,food): #实例方法也可以使用参数传递
print(food)
pass
@classmethod #用 @classmethod 来修饰的就是 类方法
def add(cls):
print('春我部')
pass
@staticmethod # @staticmethod 来修饰的就是 静态方法
def gettime():
print(time.strftime("%H:%M:%S",time.localtime())) #打印当前时间
pass
pass
xiaoxin=Labixiaoxin('小白','幼稚园','娜娜子')
print(xiaoxin.love)
xiaoxin.eat('动感汉堡')
Labixiaoxin.gettime()
#输出:
#娜娜子
#动感汉堡
#09:33:25
- 在“方法”外部定义的变量称之为-------类属性
- 在"方法"内部定义且使用self关键字的变量称之为-------实例属性
- "方法"可以传递参数,类似函数的使用
- 类属性是可以被类对象和实例对象共同访问的
- 实例属性只能被实例对象访问
- 用 @classmethod 来修饰的就是--------------------------------类方法
- 在类方法中 可以修改类属性
- @staticmethod 来修饰的且一般使用cls关键字来修饰称之为-----------------------------------静态方法
- 一般情况下 不会使用实例对象去访问静态方法,静态方法中不会涉及到类方法和类属性的操作
1.2、魔术方法
class Labixiaoxin:
name='小新' #在方法外部定义的变量称之为 类属性
age='5'
def __init__(self,dogname,job,love): # __init__ 在创建对象是由编译器自动执行
self.dogname=dogname #定义在方法内部且使用self定义的的数据称之为 实例属性
self.job=job
self.love=love
print('------执行__init__------------')
pass
def eat(self,food): #实例方法也可以使用参数传递
print(food)
pass
def __new__(cls, *args, **kwargs): #__new__ :创建并返回一个实例对象,调用一次就会得到一个对象 cls 是class的缩写
print('------执行__new__---------------')
return object.__new__(cls) #在这里创建真真的对象实例 必须有return
pass
def __str__(self): #__str__ :直接打印对象
return '我是%s,年龄%s岁,宠物叫%s,现在上%s,喜欢%s'%(self.name,self.age,self.dogname,self.job,self.love)
pass
pass
xiaoxin=Labixiaoxin('小白','幼稚园','娜娜子姐姐')
print(xiaoxin)
#------执行__new__---------------
#------执行__init__------------
#我是小新,年龄5岁,宠物叫小白,现在上幼稚园,喜欢娜娜子姐姐
-
“__init__” 在创建对象是由编译器自动执行
-
“__new__ ” 创建并返回一个实例对象,调用一次就会得到一个对象 cls 是class的缩写 , 必须有retrun才会创建一个对象
-
__str__ :直接打印对象
- 创建一个对象时,先执行 “__new__ ” 再执行 “__init__”
1.3、实例----双人决斗游戏
'''
属性: 角色名
血量
方法:
#JJJJ 普通攻击 -5血量
#unique skill 大招 -20血量
#healing 治疗 +4血量
'''
#1、定义一个类
class Hero:
#2、初始化类的属性
def __init__(self,name,hp):
self.name=name
self.hp=hp
self.sking=0
pass
#编写普通攻击的方法
def JJJJ(self,enemy):
enemy.hp-=5
if self.sking<10:
self.sking+=1 #普攻10次积攒大招
pass
print('[%s]攻击了[%s],使对方HP减少到[%d].'%(self.name,enemy.name,enemy.hp),end=' ')
pass
#编写大招攻击方式
def unique_skill(self,enemy):
enemy.hp -= 20
self.sking=0 #清空大招能量
print('[%s]释放了大招,使[%s]HP减少到[%d].' %(self.name, enemy.name,enemy.hp),end=' ')
pass
#编写治疗方式
def healing(self):
self.hp+=10
print('[%s]使用了治疗术,恢复4HP,当前HP[%d].' % (self.name,self.hp),end=' ')
pass
def __str__(self):
return '自身还剩[%d]HP,能量值积攒到[%d]'%(self.hp,self.sking)
pass
#创建两个实例化对象
xmcx=Hero('西门吹雪',100)
dgqb=Hero('独孤求败',100)
import time #加载时间函数
import random #加载随机数
while True:
if xmcx.hp==0 or dgqb.hp==0:
break
a=random.randint(1,2) #生成1~2的随机数
if a==1:
xmcx.JJJJ(dgqb)
print(xmcx)
pass
else:
dgqb.JJJJ(xmcx)
print(dgqb)
pass
if xmcx.sking>=10:
xmcx.unique_skill(dgqb) #西门吹雪 释放大招
print(xmcx)
pass
elif dgqb.sking>=10:
dgqb.unique_skill(xmcx) #独孤求败 释放大招
print(dgqb)
pass
time.sleep(1) #延时1s
pass
print('---------------------------决斗结束---------------------------')
if xmcx.hp!=0:
print('----------------------[西门吹雪]获胜-----------------------')
pass
else:
print('-----------------------[独孤求败]获胜----------------------')
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[95]. 自身还剩[100]HP,能量值积攒到[1]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[90]. 自身还剩[100]HP,能量值积攒到[2]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[85]. 自身还剩[100]HP,能量值积攒到[3]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[95]. 自身还剩[85]HP,能量值积攒到[1]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[80]. 自身还剩[95]HP,能量值积攒到[4]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[90]. 自身还剩[80]HP,能量值积攒到[2]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[75]. 自身还剩[90]HP,能量值积攒到[5]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[85]. 自身还剩[75]HP,能量值积攒到[3]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[70]. 自身还剩[85]HP,能量值积攒到[6]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[80]. 自身还剩[70]HP,能量值积攒到[4]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[75]. 自身还剩[70]HP,能量值积攒到[5]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[70]. 自身还剩[70]HP,能量值积攒到[6]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[65]. 自身还剩[70]HP,能量值积攒到[7]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[60]. 自身还剩[70]HP,能量值积攒到[8]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[55]. 自身还剩[70]HP,能量值积攒到[9]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[50]. 自身还剩[70]HP,能量值积攒到[10]
# [西门吹雪]释放了大招,使[独孤求败]HP减少到[30]. 自身还剩[70]HP,能量值积攒到[0]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[25]. 自身还剩[70]HP,能量值积攒到[1]
# [独孤求败]攻击了[西门吹雪],使对方HP减少到[65]. 自身还剩[25]HP,能量值积攒到[7]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[20]. 自身还剩[65]HP,能量值积攒到[2]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[15]. 自身还剩[65]HP,能量值积攒到[3]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[10]. 自身还剩[65]HP,能量值积攒到[4]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[5]. 自身还剩[65]HP,能量值积攒到[5]
# [西门吹雪]攻击了[独孤求败],使对方HP减少到[0]. 自身还剩[65]HP,能量值积攒到[6]
# ---------------------------决斗结束---------------------------
# ----------------------[西门吹雪]获胜-----------------------
1.4 析构方法
class Animal:
def __init__(self,name):
self.name=name
print('对象被初始化')
pass
def __del__(self):
print('当程序运行结束,解析器会自动的调用此函数 来释放内存')
print('【%s】 这个对象被彻底删除了,内存也被释放了,这就是【析构方法】'%(self.name))
pass
pass
cat=Animal('蓝猫')
input('--------------等待输入---------')
dog=Animal('二哈')
#当手动删除某个对象时,也会调用析构方法
del dog #收到删除dog对象 #当对象被删除后,则不能再被使用
# 对象被初始化
# --------------等待输入---------
# 对象被初始化
# 当程序运行结束,解析器会自动的调用此函数 来释放内存
# 【二哈】 这个对象被彻底删除了,内存也被释放了,这就是【析构方法】
# 当程序运行结束,解析器会自动的调用此函数 来释放内存
# 【蓝猫】 这个对象被彻底删除了,内存也被释放了,这就是【析构方法】
- 析构方法 即 当使用完某个对象之后,将其删除用于释放内存
- 或者是程序结束运行时将对象释放,从而释放内存
1.5 继承
#单继承:子类可以继承父类【属性和行为】(爸爸有的儿子都有,儿子有的爸爸不一定有)
class Animal:
def eat(self):
print('【%s】爱吃肉'%(self.name))
pass
def drink(self):
print('【%s】爱喝牛奶'%(self.name))
pass
def __init__(self,name):
self.name=name
print('【%s】 __init__' % (self.name))
pass
def __del__(self):
print('【%s】 __del__'%(self.name))
pass
pass
class dog(Animal): #继承Animal父类
def wwj(self):
print('【%s】汪汪叫'%(self.name))
pass
pass
class cat(Animal): #继承Animal父类
def mmj(self):
print('【%s】喵喵叫'%(self.name))
pass
pass
D=dog('小狗')
D.wwj()
D.eat()
C=cat('小猫')
C.mmj()
C.drink()
#多继承 继承Animal、dog、cat三个父类,因为dog,cat继承了Animal所以这里不用再写一次 这个叫做【简介继承】
class Pets(dog,cat):
def DealShit(self):
print('要铲屎官')
pass
def __init__(self,name):
self.name=name
pass
pass
#peop对象继承了三个类, A
people=Pets('铲屎官')
people.eat()
people.drink()
people.mmj()
people.wwj()
#当多个父类中存在相同的方法时 ,会根据定义【类】时的顺序查找 【自身>继承的第一个类>继承的第二个类】即广度优先原则
#这种原则下可实现 , 在子类中有与父类相同名字的方法,则子类会覆盖掉父类的方法, 即方法覆盖/重写
# 【小狗】 __init__
# 【小狗】汪汪叫
# 【小狗】爱吃肉
# 【小猫】 __init__
# 【小猫】喵喵叫
# 【小猫】爱喝牛奶
# 【铲屎官】爱吃肉
# 【铲屎官】爱喝牛奶
# 【铲屎官】喵喵叫
# 【铲屎官】汪汪叫
# 【小狗】 __del__
# 【小猫】 __del__
# 【铲屎官】 __del__
- 继承:子类可以继承父类【属性和行为】(爸爸有的儿子都有,儿子有的爸爸不一定有)
- 当一个新的对象继承的类继承了另外一个类,这样新的对象则继承了两个类-----------------------------------间接继承
-
当多个父类中存在相同的方法时 ,会根据定义【类】时的顺序查找 【自身>继承的第一个类>继承的第二个类】---------------------------广度优先原则
-
在子类中有与父类相同名字的方法,则子类会覆盖掉父类的方法, ----------------------------------------------方法覆盖/重写
-
1.6 多态
#多态:多种形态,就是同一种行为,对于不同的【子类对象】有不同的行为表现
#多态的条件:
#1. 继承:发生在父类和子类之间
#2. 重写:子类重写父类的方法
class Animal:
def Say_who(self):
print('说我是一个动物')
pass
pass
class Dack(Animal):
def Say_who(self): #重写父类的方法
print('我是可达鸭' )
pass
pass
class Bird(Animal):
def Say_who(self):
print('我是巴达兽')
pass
pass
class baolongshou(Animal):
def Say_who(self):
print('我是战斗暴龙兽')
pass
pass
def commonInvoke(obj):
obj.Say_who() #动态语言的动态类型 只要函数名(方法),且参数一样 不管前面的对象是谁,都可以通过这个方法输出
pass
# dack=Dack('可达鸭')
# dack.Say_who()
listobj=[Dack(),Bird(),baolongshou()] #这种方式可以在不修改原代码的情况下任意的添加对象
for i in listobj:
commonInvoke(i) #多态可以增加程序的灵活性 和 扩展性
pass
# 我是可达鸭
# 我是巴达兽
# 我是战斗暴龙兽
-
多态:多种形态,就是同一种行为,对于不同的【子类对象】有不同的行为表现
-
多态的条件:1. 继承:发生在父类和子类之间 2. 重写:子类重写父类的方法
-
动态语言的动态类型只要函数名(方法),和参数一样 不管前面的对象是谁,都可以通过这个方法输出
-
多态可以增加程序的灵活性 和 扩展性
1.7 私有化属性/方法
私有化的应用场景:
-
不让类的外部进行直接调用
-
不让属性的值随意修改
-
不让派生类【子类】继承
-
属性前加两个下划线“__”,则此属性被私有化
1.71 私有化属性
#私有属性/方法的应用场景
#1.保护属性,不让类的外部进行直接调用
#2.保护属性,不让属性的值随意修改
#3.保护属性,不让派生类【子类】继承
class person:
def __init__(self):
self.__name='八神.太一' #属性前加两个下划线“__”,则此属性被私有化
self.age=10
self.flag='勇气徽章'
pass
def __str__(self):
return '【%s】的年龄是[%d]岁'%(self.__name,self.age)
pass
yagushou=person()
#print(person.__name) #私有化的属性是不能再类的外部使用的 这样编译会出错
print(yagushou)
#【八神.太一】的年龄是[10]岁
1.72 私有化方法
#私有化方法
class Digimon:
def __init__(self):
self.__name='亚古兽' #私有化属性
pass
def __Ultima(self): #私有化方法
print('【盖亚能量炮】')
pass
def Run(self):
print('【%s】进化了,并释放了'%(self.__name),end=' ')
self.__Ultima() #调用私有化方法
pass
pass
a=Digimon()
a.Run() #上面都是通过【类】内部的【方法】访问了【私有属性/方法】
#也可以------通过【属性】的方式访问【私有属性】
#【亚古兽】进化了,并释放了 【盖亚能量炮】
1.8单例模式
单例模式 是一种常用的软件设计模式 , 目的是:确保某一个【类】值有一个实例存在,即一个【类】只能创建一个【对象】
#单例模式 是一种常用的软件设计模式 目的是:确保某一个【类】值有一个实例存在
#即一个【类】只能创建一个【对象】
#创建一个单例对象 基于__new__实现
class Digimon:
def __init__(self):
self.__name='亚古兽' #私有化属性
pass
def __new__(cls, *args, **kwargs):
#cls.Once=cls.__new__(cls) #不能使用自身的new方法 容易造成深度递归,
if not hasattr(cls,'Once'):#如果不存在则开始创建 hasattr函数用于判断对象是否包含对应的属性。
cls.Once=super().__new__(cls,*args, **kwargs) # 应该调用父类的new方法 ,super 表示 调用父类方法
return cls.Once
pass
a1=Digimon()
print(id(a1))
a2=Digimon()
print(id(a2))
#通过ID函数可以看出,假如是单例模式 只会创建一个对象
#1948826947344
#1948826947344
1.9 异常处理
即代码执行出现异常,则会跳到指定的代码块,以下是应用举例。
#自定义异常
class ErrorToLong(Exception):
def __init__(self,len):
self.len=len
pass
def __str__(self):
return '输入的长度为'+str(self.len)+'超长了'
pass
try:
name = input('请输入名字\n')
if len(name) > 4:
raise ErrorToLong(len(name)) # raise 后带一个异常类名称,表示引发执行类型的异常
else:
print('输入的名字是[%s]'%name)
pass
print('我是try') #捕获逻辑的代码
pass
except NameError as msg: #捕获命名错误
print(msg)#捕获到错误,才会执行到这里
pass
except IndexError as msg: #捕获下标错误
print(msg)
pass
except Exception as msg: #可捕获所有错误类型
print(msg)
pass
else: #没有出错会执行到这里
print('当try里的代码执行,我才会执行')
pass
finally: #不管有没有出错出错都会执行到这里
print('我不管有没有出错 都会执行')
pass
1.10 __slots__ 使用
只有在__slots__变量中的属性才能被添加,没有再其中的属性会添加失败。这种机制可以防止其他人调用类的时候胡乱添加属性和方法。__slots__属性子类不能继承,只有在当前类中有效。
使用 __slots__可节约内存空间
#__slots__ 只有在__slots__变量中的属性才能被添加,没有再其中的属性会添加失败。
#这种机制可以防止其他人调用类的时候胡乱添加属性和方法
#__slots__属性子类不能继承,只有在当前类中有效
class Student(object):
__slots__= ('name','age') #限制只有这两种属性
def __str__(self):
return '【%s】的年龄是【%d】'%(self.name,self.age)
pass
xw=Student()
xw.name='小王'
xw.age=18
print(xw)
print(xw.__dict__) #假如不使用__slots__所有的属性都会存放在这里,
#定义了__slots__之后,类的实例就不能随意创建属性了,同时__dict__里不会再有数据了,从而节约内存空间
#xw.aaa=822 #不允许添加__slots__之外的属性
class substance(Student):
__slots__=()
pass
#如果子类中没有声明__slots__,那么不会继承父类的__slots__内容
#如果子类中 声明了__slots__,那么就会继承父类找那个__slots__的内容