目录
复习知识点
析构方法
当一个对象被删除或者被销毁时,python解释器也会默认调用一个方法,这个方法为__del__()方法
单继承
子类在继承的时候,在定义类时,小括号()中为父类的名字 父类的属性、方法,会被继承给子类。
多继承
子类可以继承多个父类,在小括号()中用逗号隔开
继承的传递
子类可以继承父类的父类的方法
重写和调用父类方法
重写父类方法后,调用的是子类的方法。
在重写的方法里面还可以调用父类方法。
多态
定义时的类型和运行时的类型不一样,此时就成为多态。
类属性和实例属性
类属性:就是类对象所拥有的属性
实例属性:实例对象所拥有的属性
类方法和静态方法
用@classmethod来表示类方法
用@staticmethod来表示静态方法
1.私有化属性
概述
前面学习面向对象过程中,修改类属性都是直接通过类名修改的。如果有些重要属性不想让别人随便修改,或者防止意外修改,该怎么办?
为了更好的保存属性安全,即不能随意修改,将属性定义为私有属性,添加一个可调用的方法去访问。
语法
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。
示例
class Person():
def __init__(self):
self.name='李四'
self.__age=30 # 加两个下划线,将此属性私有化
def __str__(self):
return '{}的年龄是{}'.format(self.name,self.__age)
pass
class student(Person):
def printInFo(self):
print(self.__age) #在此访问父类中的私有属性,是可以的
pass
stu=student()
print(stu.name)
#print(stu.__age) #继承后不能被调用
Xm=Person()
print(Xm.name) #实例对象可以调用公有属性
print(Xm)
#print(Person.__age) #类对象外部无法访问私有类属性
#print(XM.__age) #实例对象外部无法访问私有类属性
输出结果会报错
小结:
1.私有化属性不能在类外面访问。
2.私有化属性可以在类里面访问,修改
3.子类不能继承私有化属性
2.私有化方法
概述
私有化方法跟私有化属性概念一样,有些重要的方法,不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法。
语法
私有化方法,即在方法名前面加两个下划线
示例
class Animal:
def __eat(self): #加双下划线就是私有化了
print('吃东西')
pass
def run(self):
self.__eat() #在此调用私有化方法
print('飞快的跑')
pass
class Bird(Animal):
pass
b1=Bird()
#b1.__eat() #会报错 子类不能调用父类的私有化方法
b1.run()
输出结果
吃东西
飞快的跑
特性
私有化方法一般是类内部调用,子类不能继承,外部不能调用
单下划线、双下划线、头尾双下划线说明
xxx 前面加一个下划线,以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能使用from xxx import * 的方式导入。
__xxx__ 前后两个下滑线,魔法方法,一般是python自有,开发者不要创建这类型的方法。
xxx_ 后面单下滑线,避免属性名与python关键字冲突。
3.Property属性
概述
上节我们讲了访问私有变量的话,一般写两个方法一个访问,一个修改,由方法去控制访问。
class Person():
def __init__(self):
self.__age = 18 # 定义一个私有化属性,属性名字前加连个 __ 下滑线
def get_age(self):# 访问私有类属性
return self.__age
def set_age(self,age): #修改私有化属性
if age < 0:
print('年龄不能小于')
else:
self.__age = age
这样给调用者的感觉就是调用了一个方法,并不是访问属性。我们怎么做到让调用者直接以访问属性的方式,而且我们又能控制的方式提供给调用者?
Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情。
实现方式-1
类属性,即在类中定义值为property对象的类属性
示例:给age属性设置值时,会自动调用setage方法,获取age属性值时,会自动调用getage方法。
class Person():
def __init__(self):
self.__age = 18 # 定义一个私有化属性,属性名字前加连个 __ 下滑线
def get_age(self):# 访问私有类属性
return self.__age
def set_age(self,age): #修改私有化属性
if age < 0:
print('年龄不能小于0')
else:
self.__age = age
''' 定义一个类属性,实现通过直接访问属性的形式去访问私有属性'''
age=property(get_age,set_age)
Xm=Person()
Xm.age=15
print(Xm.age)
实现方式-2
装饰器,即在方法上使用装饰器
class Person():
def __init__(self):
self.__age = 18 # 定义一个私有化属性,属性名字前加连个 __ 下滑线
@property #用装饰器修饰,添加属性标识
def age(self):# 访问私有类属性
return self.__age
@age.setter #使用装饰器对age进行装饰,提供一个getter方法
def age(self,parm): #修改私有化属性
if parm < 0:
print('年龄不能小于0')
else:
self.__age = parm
Xm=Person()
Xm.age=15
print(Xm.age)
4.__new___方法
概述
_new_方法的作用是,创建并返回一个实例对象,如果__new__只调用了一次,就会得到一个对象。继承自object的新式类才有new这一魔法方法。
注意事项:
__new__ 是在一个对象实例化的时候所调用的第一个方法
__new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供 ,其他的参数是用来直接传递给 __init__ 方法
__new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用
在__new__ 方法中,不能调用自己的__new__ 方法,即:return cls.__new__ (cls),否则会报错(RecursionError: maximum recursion depth exceeded:超过最大递归深度)
使用方式-1
class Animal:
def __init__(self):
print('__init__执行啦')
self.colour='红色'
pass
'''如果在Python中不重写new方法,默认如下结果'''
def __new__(cls,*args,**kwargs):
print('__new__执行啦')
return super().__new__(cls,*args,**kwargs) #用super()或者objec()调用 不能用cls调用
pass
tigger=Animal() #实例化的过程会自动调用 __new__去创建实例
'''
在新式类中,__new__才是真实的实例化方法,为类提供外壳制造出实例框架,
然后调用该框架内的构造方法__init__进行丰满操作
'''
运行结果
__new__执行啦 备注:__new__方法先被调用
__init__执行啦
5.单例模式
概述
单例模式是常用设计模式的一种,单例就比如我们打开电脑的回收站,在系统中只能打开一个回收站,也就 是说这个整个系统中只有一个实例,重复打开也是使用这个实例。
简单的说就是不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象。
实现步骤-1
利用类属性保存初次创建的实例对象,第二次实例化的时候判断类属性是否有保存实例对象,如果有就返回类属性保存的,如果没有就调用父类__new__方法创建新的实例对象。
class DataBaseClass():
def __new__(cls, *args, **kwargs):
'''
cls._instance=cls.__new__(cls)
不能调用自己的__new__ 方法,否则会造成死循环
'''
if not hasattr(cls,'_instance'): #如果不存在就开始创建
cls._instance=super().__new__(cls, *args, **kwargs)
return cls._instance
pass
class DBoptsingle(DataBaseClass):
pass
'''每次输出的结果都不一样'''
db1=DataBaseClass()
print(id(db1))
db2=DataBaseClass()
print(id(db2))
db3=DBoptsingle()
print(id(db3))
db4=DBoptsingle()
print(id(db4))
输出结果
1846350089232
1846350089232
1846350089232
1846350089232
6.错误与异常处理
概述
有时候代码写错了,执行程序的时候,执行到错误代码的时候,程序直接终止报错,这是因为Python检测到一个错误时,解释器就无法继续执行了,出现了错误的提示,这就是"异常"。
语法格式
try:
可能出现错误的代码块
except:
出错之后执行的代码块
else:
没有出错的代码块
finally:
不管有没有出错都执行的代码块
try ... except 语句
将可能出错的代码放到try里面,except可以指定类型捕获异常。except里面的代码是捕获到异常时执行,将错误捕获,这样程序就不会因为一段代码包异常而导致整个程序崩溃。
示例
try:
print(b) #捕获逻辑的代码
except NameError as msg:
'''捕获到的错误才会在这里执行'''
print(msg)
pass
print('初次接触异常')
print('HHHHHHH')
运行结果
name 'b' is not defined #爆出错误
初次接触异常 #后面程序可以照常执行
HHHHHHH
可以捕获所有异常用 Exception
示例
try:
#print(b)#逻辑的代码
li=[1,2,3,31]
print(li[10]) #通过下标去访问列表
# except NameError as msg1:
# '''捕获到的错误才会在这里执行'''
# print(msg1)
# pass
# except IndexError as msg:
# '''捕获到的错误才会在这里执行'''
# print(msg)
# pass
except Exception as result: #可以捕获所有的异常
'''捕获到的错误才会在这里执行'''
print(result)
pass
print('初次接触异常')
print('HHHHHHH')
不需要在每个可能出错的地方去捕获,只要在合适的层次去捕获错误就可以了 这样的话可以大大减少try.......except 的麻烦
异常的抛出机制
如果在运行时发生异常,解释权会直接查找相应的异常捕获类型
如果在当前函数里面没有找到的话,它会将异常传递给上层的调用函数
如果在最外层还没找到的话,解释器就退出,程序断掉
自定义异常
自定义异常,都要直接或间接继承Error或Exception类
由开发者主动抛出自定义异常,在python中使用raise关键字
class ToolException(Exception): # 自定义异常类需要继承Exception
def __init__(self,leng):
self.len=leng
def __str__(self):
return '您输入姓名数据长度是'+str(self.len)
pass
def name_Test():
name=input('请输入姓名:')
try:
if len(name)>5:
'''# raise 关键字抛出异常 '''
raise ToolException(len(name))
else:
print(name)
except ToolException as result:
print(result) # 捕获异常
finally:
print('执行完毕了')
name_Test()
输出结果
请输入姓名:hhhhhhh
您输入姓名数据长度是7
执行完毕了
7.Python动态添加属性和方法
概述
动态语言:运行时可以改变其结构的语言,例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。如php,JavaScript,python都是动态语言,C,C#,java是静态语言。
所以python可以在程序运行过程中添加属性和方法。
class Animal():
def __init__(self,name,age):
self.name=name
self.age=age
'''定义了两个初始属性name和age,后面再添加colour'''
def __str__(self):
return '{}的颜色是{},今年{}岁啦,有{}条腿'.format(self.name,self.colour,self.age,self.foot)
Animal.foot=4 #添加类属性,实例属性可以调用添加的类属性
cat=Animal('小白',5)
cat.colour='白色' #动态绑定实例属性的colour属性
print(cat)
print(cat.foot) #实例属性可以调用添加的类属性,返回值是4
#print(Animal.colour) #动态添加的实例属性,类属性不能调用,会报错
运行结果
小白的颜色是白色,今年5岁啦,有4条腿
4
动态添加实例方法需要使用types
import types
def weightMethod(self):
print('{}的体重是{}kg,有{}条腿'.format(self.name,self.weight,Animal.foot))
'''可以调用实例属性也可以调用类属性'''
pass
class Animal():
def __init__(self,name,age):
self.name=name
self.age=age
'''定义了两个初始属性name和age,后面再添加colour'''
def __str__(self):
return '{}的颜色是{},今年{}岁啦,有{}条腿'.format(self.name,self.colour,self.age,self.foot)
Animal.foot=4 #添加类属性,实例属性可以调用添加的类属性
cat=Animal('小白',5)
cat.weight=15
cat.printInfo=types.MethodType(weightMethod,cat)
cat.printInfo() #调用动态绑定的方法
cat.colour='白色' #动态绑定实例属性的colour属性
print(cat)
print(cat.foot) #实例属性可以调用添加的类属性,返回值是4
#print(Animal.colour) #动态添加的实例属性,类属性不能调用,会报错
运行结果
小白的体重是15kg,有4条腿
小白的颜色是白色,今年5岁啦,有4条腿
4
给类绑定类方法和静态方法
使用方式:类名.方法名 = xxxx
import types #添加方法的库
def dymicMethod(self):
print('{}的体重是:{}kg 在 {} 读大学'.format(self.name,self.weight,Student.shcool))
pass
@classmethod
def classTest(cls):
print('这是一个类方法')
pass
@staticmethod
def staticMethodTest():
print('这是一个静态方法')
pass
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
def __str__(self):
return '{}今天{}岁了'.format(self.name,self.age)
pass
print('绑定类方法')
Student.TestMethod=classTest
# Student.TestMethod()
Student.staticMethodTest=staticMethodTest
Student.staticMethodTest()
print('---------------绑定类方法执行结束----------------------')
zyh=Student('张艳华',20)
zyh.weight=50 #动态添加
zyh.printInfo=types.MethodType(dymicMethod,zyh) #动态的绑定方法
zyh.TestMethod()
print('-------------实例对象调用 动态绑定类方法-----------------------')
# print(zyh)
# print(zyh.weight)
print('-------------另外一个实例对象 张明--------------------------')
zm=Student('张名',20)
zm.weight=80 #动态添加
print(zm)
zm.printInfo=types.MethodType(dymicMethod,zm) #动态的绑定方法
# print(zm.weight)
print('-------------给类对象添加属性--------------------------')
Student.shcool='北京邮电大学' #动态添加类属性
print(zm.shcool)
print('-------------执行动态调用实例方法--------------------------')
zyh.printInfo() #调用动态绑定的方法
zm.printInfo()
运行结果
绑定类方法
这是一个静态方法
---------------绑定类方法执行结束----------------------
这是一个类方法
-------------实例对象调用 动态绑定类方法-----------------------
-------------另外一个实例对象 张明--------------------------
张名今天20岁了
-------------给类对象添加属性--------------------------
北京邮电大学
-------------执行动态调用实例方法--------------------------
张艳华的体重是:50kg 在 北京邮电大学 读大学
张名的体重是:80kg 在 北京邮电大学 读大学
8.__slots___属性
概述
python是动态语言,在运行的时候可以动态添加属性。如果要限制在运行的时候给类添加属性,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。
只有在__slots__变量中的属性才能被添加,没有在__slots__变量中的属性会添加失败。可以防止其他人在调用类的时候胡乱添加属性或方法。__slots__属性子类不会继承,只有在当前类中有效。
class Student():
__slots__ = ('name','age')
def __str__(self):
return '{}的年龄是{}岁'.format(self.name,self.age)
xw=Student()
xw.name='小王'
xw.age=20
#xw.score=96 #不在slots范围内,不能添加
print(xw)
print('-----------在继承中的使用---------')
class subStudent(Student):
pass
ln=subStudent()
ln.gender='男'
ln.pro='计算机'
print(ln.gender,ln.pro)
输出结果
小王的年龄是20岁
小王的年龄是20岁
-----------在继承中的使用---------
男 计算机
__slots___属性特性
1.限制添加属性
2.可以节约内存空间
3.子类继承父类的__slots___属性中已经存在的属性,但是其可以新增不在slots中的属
知识总结
私有化属性
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。
私有化方法
私有化方法,即在方法名前面加两个下划线。
Property属性
类属性,即在类中定义值为property对象的类属性
装饰器,即在方法上使用装饰器
__new__方法
_new_方法的作用是,创建并返回一个实例对象
单例模式
不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象。
错误与异常处理
try:
可能出现错误的代码块
except:
出错之后执行的代码块
else:
没有出错的代码块
finally:
不管有没有出错都执行的代码块
Python动态添加属性和方法
在程序运行过程中添加属性和方法
__slots__方法
在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
课后问答题
1、Python中new方法作用是什么?
_new_方法的作用是,创建并返回一个实例对象。只有继承了object的话,才能有这个方法
2、什么是单例模式?单例模式适用于什么场景?
单例模式是常用设计模式的一种。简单的说就是不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象。
场景:日志插入logger的操作,网站计数器,权限验证模块,window资源管理器,系统回收站,数据库连接池
3、私有化方法与私有化属性在子类中能否继承?
私有化属性不能在类的外部被使用或直接访问,子类不能继承私有化属性
私有化方法一般是类内部调用,子类不能继承,外部不能调用
4、在Python中什么是异常?
有时候代码写错了,执行程序的时候,执行到错误代码的时候,程序直接终止报错,这是因为Python检测到一个错误时,解释器就无法继续执行了,出现了错误的提示,这就是"异常"。
5、Python中是如何处理异常的。
分别根据异常的类型去处理
6、Python中异常处理语句的一般格式,可以使用伪代码的形式描述。
try:
可能出现错误的代码块
except:
出错之后执行的代码块
else:
没有出错的代码块
finally:
不管有没有出错都执行的代码块
7、__slots__属性的作用
python是动态语言,在运行的时候可以动态添加属性。如果要限制在运行的时候给类添加属性,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。
(1)限制属性的随意输入
(2)节省内存空间__dict__
8、私有化属性的作用?
为了更好的保存属性安全,即不能随意修改,将属性定义为私有属性,添加一个可调用的方法去访问。
9、在类外面是否能修改私有属性。
私有化属性不能在类外面修改,通过方法去实现,还可以借助属性函数property去实现
10、如果一个类中,只有指定的属性或者方法能被外部修改。那么该如何限制外部修改。
对属性进行私有化的设定
课后实操题
1、编写一段代码以完成下面的要求
class Person():
# 定义一个Person类,类中要有初始化方法,方法中要有人的姓名,年龄两个私有属性.
def __init__(self,name,age):
self.__name=name
self.__age=age
# 提供获取用户信息的函数.
def __str__(self):
return "{}的年龄是{}".format(self.__name,self.__age)
#提供获取私有属性的方法.get
def getInfo(self):
return self.__age
#提供可以设置私有属性的方法.set
def setAge(self,age):
#设置年龄的范围在(0-120)的方法,如果不在这个范围,不能设置成功.
if age>0 and age<0:
self.__age=age
else:
print('您输入的数据不合法')
def getInfo(self):
return self.__name
def setName(self,name):
self.__name=name
2、请写一个单例模式
class SingleCase(object):
__instance = None # 保存实例对象
def __init__(self,name,age):
print(name,age)
def __new__(cls, *args, **kwargs):
# 如果类属性 __instance 的值为None,那么新建一个对象
# 如果类属性值不为None 返回 __instance 保存的对象
if not cls.__instance:
cls.__instance = super(SingleCase,cls).__new__(cls) # 调用父类__new__方法生成一个实例对象
return cls.__instance
else:
return cls.__instance
3、创建一个类,并定义两个私有化属性,提供一个获取属性的方法,和设置属性的方法。利用property 属性给调用者提供属性方式的调用获取和设置私有属性方法的方式。
class Student():
def __init__(self):
self.__name='张三'
self.__score='90'
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name=name
@property
def score(self):
return self.__score
@score.setter
def score(self,score):
self.__score=score
def __str__(self):
return ''
def __call__(self, *args, **kwargs):
print(self.__name+'的得分是:'+self.__score)
Xw=Student()
Xw()
Xw.name='李四'
Xw.score='98'
Xw()
print(Xw)
输出结果
张三的得分是:90
李四的得分是:98
4、创建一个Animal类,实例化一个cat对象,请给cat对象动态绑定一个run方法,给类绑定一个类属性colour,给类绑定一个类方法打印字符串'ok'。
import types
def run(self):
print('小猫飞快的跑')
@classmethod
def info(cls):
print('OK')
class Animal():
pass
Animal.colour='黑色' #绑定类属性
Animal.info=info
cat=Animal()
cat.run=types.MethodType(run,cat) #动态绑定
cat.run()
print(cat.colour)
Animal.info()
输出结果
小猫飞快的跑
黑色
OK