Python(IT峰)笔记11-面向对象高阶,内置成员,方法的分类,面向对象的常用函数,魔术方法,str和repr的区别,成员相关魔术方法,描述符,描述符三种定义方式,单例模式,MixIn模式,抽象类
作者:互联网
1、内置成员
定义完类后直接就有的成员
class Father():
pass
class Demo(Father):
'''
类的说明文档
'''
name='zhangsan'
age=20
def say(self):
print('say somthing')
res=Demo.__dict__
print(res)#{'__module__': '__main__', 'name': 'zhangsan', 'age': 20, 'say': <function Demo.say at 0x000001F03BC83700>, '__dict__': <attribute '__dict__' of 'Demo' objects>, '__weakref__': <attribute '__weakref__' of 'Demo' objects>, '__doc__': None}
obj=Demo()
obj.university='tingshua'
print(obj.__dict__)#{'university': 'tingshua'}
res=Demo.__doc__
print(res)#类的说明文档
res=obj.__doc__
print(res)#类的说明文档
#获取类名称
res=Demo.__name__
print(res)#Demo
#获取当前文件夹
res=Demo.__module__
print(res)#__main__
#获取当前类的父类列表
res=Demo.__bases__
print(res)#(<class '__main__.Father'>,)
#获取MRO列表,当前类的继承列
res=Demo.__mro__
print(res)#(<class '__main__.Demo'>, <class '__main__.Father'>, <class 'object'>)
2、方法的分类
1、对象方法:
- 在类中定义的方法,含有self参数
- 含有self的方法,只能通过对象调用
- 该方法把调用的对象传递进来
2、类方法
在类中定义的方法,使用类装饰器@classmethod进行了装饰
方法中有cls这个形参
不需要实例化对象,直接使用类进行调用
会把调用这个方法的类传递进来
3、绑定类方法
- 在类中定义的方法,不传递任何对象
- 只能使用类名来调用,不能使用对象来调用
- 不会传递对象或者类进来
4、静态方法(和java的静态方法还是有很多不同的)
- 在类中定义的方法没有参数
- 使用了装饰器符号@staticmethod进行了装饰
- 可以使用对象或类进行调用
- 不会传递任何参数进来
class Demo():
#对象方法:需要使用实例来调用,并传入self
def func1(self):
print('this is func1')
#类方法,@classmethod装饰器关键字
@classmethod
def func2(cls):
print(cls)
print('this is class funtion func2')
#绑定类方法
def func3():
print('this is bind class function func3')
#静态方法
@staticmethod
def func4():
print('this is staticmethod func4')
obj=Demo()
obj.func1()#调用对象方法this is func1
Demo.func1('hello')#使用类名调用对象方法必须传入参数
#Demo.func1()#使用类名调用对象方法不传参会报错
Demo.func2()#使用类名去调用<class '__main__.Demo'>,this is class funtion func2
obj.func2()#即便使用了对象去调用,方法里面传递的依然是类,而不是对象
#绑定类方法直接使用类调用
Demo.func3()#this is bind class function func3
#obj.func3()#不能用对象来调用,用对象来调用会报错
#静态方法可以使用类和对象进行调用
Demo.func4()#this is staticmethod func4
obj.func4()#this is staticmethod func4
3、面向对象的常用函数
- issubclass()子类检测
- isinstance()实例检测
- hasattr()检测类/对象是否包含指定名称的成员
- getattr()获取类/对象的成员的值
- setattr()设置类/对象的成员的值
- delattr()删除类/对象的成员,和del直接删除对象的成员是一样的结果
- dir()获取对象所有可以访问的成员的列表
class A():
pass
class B(A):
pass
class C(A):
pass
class D(B,C):
name='zhagnsan'
age=34
def say(self):
print('i want to say somthing')
#issubclass()子类检测
res=issubclass(D,B)
print(res)#True
#isinstance()实例检测
d=D()
res=isinstance(d,D)
print(res)#True
#hasattr()检测类/对象是否包含指定名称的成员
res=hasattr(D,'name')
print(res)#True
res=hasattr(d,'name')
print(res)#True
#getattr()获取类/对象的成员的值
res=getattr(d,'name')
print(res)#zhagnsan
#setattr()设置类/对象的成员的值
setattr(d,'name','lisi')
res=getattr(d,'name')
print(res)#lisi
print('---')
#delattr()删除类/对象的成员,和del直接删除对象的成员是一样的结果
delattr(d,'name')
print(d.name)#zhangsan,这里lisi被删除,但去保留了类里面的name,
print(D.name)#zhangsan
print('===')
delattr(D,'name')
#print(d.name)#都会报错,因为类的属性都没有了,对象的属性也不再了
#print(D.name)#都会报错
#dir()获取对象所有可以访问的成员的列表
res=dir(d)
print(res)#很多,不贴了
4、魔术方法(上)
1、__init__初始化方法
当时实例化对象之后就会立即出发的方法,完成对象的初始化操作
有个self参数,接受当前对象,其他参数根据需求定义集合
无返回值
2、__del__析构方法
当该类对象被销毁时,自动触发,用来关闭或释放对象创建时所使用的资源
有个self参数,接受当前对象
无返回值
3__new__构造方法
- 实例化对象时自动触发,在__init__之前触发
- 管理控制对象创建的过程
- 一个cls参数,接受当前类,其他参数根据初始化方法的参数进行决定
- 返回值可有可无,如果返回,必须返回object.new(cls)进行对象的创建,如果没有返回值,则实例化对象的结果为None
- __new__方法的参数和__init__方法的参数要保持一致,除了第一个参数。
- 设计模式中的单例模式往往需要用到
class Person():
# 构造方法
def __new__(cls, *args, **kwargs):
print('触发了构造方法')
print(args) # ('zhangsan', 34, 'female')
print(kwargs) # {}
# 如果没有在该方法(构造方法)中返回对象,则对象无法创建
return object.__new__(cls) # cls是当前类,将构造好的对象返回出去
def __init__(self, name, age, gender):
print('触发了初始化方法')
self.name = name
self.age = age
self.gender = gender
def __del__(self):
print('触发了析构方法')
p1 = Person('zhangsan', 34, 'female')
print(p1.name)
print(p1)
运行结果
触发了构造方法
('zhangsan', 34, 'female')
{}
触发了初始化方法
zhangsan
<__main__.Person object at 0x00000216EE079400>
触发了析构方法
4__call__
- 把对象当作函数直接调用时自动触发
- 一般用于归纳类或对象的操作步骤,方便调用
- 一个self参数接收当前对象,其他参数根据调用需求决定
- 返回值可有可无
class Person():
# 构造方法
def __new__(cls, *args, **kwargs):
print('触发了构造方法')
print(args) # ('zhangsan', 34, 'female')
print(kwargs) # {}
# 如果没有在该方法(构造方法)中返回对象,则对象无法创建
return object.__new__(cls) # cls是当前类,将构造好的对象返回出去
def __init__(self, name, age, gender):
print('触发了初始化方法')
self.name = name
self.age = age
self.gender = gender
def __del__(self):
print('触发了析构方法')
def __call__(self, *args, **kwargs):
print('你把对象当成了函数调用')
p1 = Person('zhangsan', 34, 'female')
print(p1.name)
print(p1)
p1()#你把对象当成了函数调用
5、魔术方法(下)
1、len
当使用len函数去检测当前对象的时候自动触发
可以使用len函数检测当前对象中某个数据的信息
一个self参数,接受当前对象
必须要有返回值,并且必须是一个整型
len要获取什么属性的值,就在返回值中返回那个属性的长度集合
class Demo():
listur=[1,3,5,6]
#可以替代对象使用len函数,并返回一个指定的整型数
def __len__(self):
return len(self.listur)
obj=Demo()
res=len(obj)
print(res)#4
2、str
- 当使用str或print函数对对象进行操作时触发
- 对对象进行字符串的返回,可以自定义返回的字符串
- 需要一个self参数,接收当前对象
- 返回值必须要有,并且是字符串类型的值
class Demo():
listur=[1,3,5,6]
#可以替代对象使用str函数,并返回一个自定义的字符串
def __str__(self):
return '本脚本,Demo object字符转换'
obj=Demo()
res=str(obj)#本脚本,Demo object字符转换,转换字符串操作。使用的是继承自object类的str函数
print(res)
print(obj)#本脚本,Demo object字符转换,转换字符串操作,实际是自定义了一个属于自己的str函数
3、repr
- 上例中,如果没有使用__str__方法,也可以使用__repr__方法替换
- 在使用repr方法对当前对象进行转换时自动触发
- 可以设置repr函数操作对象的结果
- 需要一个self参数,接收当前对象
- 返回值必须要有,并且是字符串类型的值
- 正常情况下__str__方法和__repr__方法是可以互相替代的
class Demo():
listur=[1,3,5,6]
#可以替代对象使用str函数,并返回一个自定义的字符串
# def __str__(self):
# return '本脚本,Demo object字符转换'
def __repr__(self):
return '本脚本,Demo object字符转换'
obj=Demo()
res=str(obj)#本脚本,Demo object字符转换,转换字符串操作。使用的是继承自object类的str函数
print(res)
print(obj)#本脚本,Demo object字符转换,转换字符串操作,实际是自定义了一个属于自己的str函数
4、bool
当使用bool函数转换当前对象时,会自动触发,默认情况下,对象会转为True
可以代替对象进行bool类型的转换,可以转换任意数据
self参数接收对象
必须返回一个bool类型的返回值
class Demo():
listur=[]
def __bool__(self):
return bool(self.listur)
obj=Demo()
res=bool(obj)
print(res)#False,如果没有魔术方法,返回True
6、str和repr的区别
都可以转换其他类型的值为字符串
repr解析出来的值带引号
str函数会把对象转为更适合人类阅读的形式
repr函数会把对象转为解释器读取的形式
7、成员相关魔术方法
1、getattribute
- 当访问对象成员时自动触发,无论当前成员是否存在
- 可以在获取对象成员时,对数据进行一些处理
- 需要一个self参数,接收对象,一个item接收当前访问的成员名称
- 返回值可有可无,返回值就是访问的结果
- 在当前魔法方法中,禁止对当前对象的成员访问,因为会触发递归。
- 如果要在当前魔术方法中访问对象成员必须使用object.getattribute(self,item)进行访问
2、getattr
- 当访问对象不存在的成员时,自动触发
- 防止访问不存在的成员时报错,也可以为不存在的成员进行赋值操作
- 需要一个self参数接收当前对象,一个item接受当前访问的成员名称
- 当存在__getattribute__的方法时,会去执行这个__getattribute__方法因为这个方法优先级gao
class Person():
name='name'
age=34
gender='male'
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def say(self):
print('talk somthing')
def sing(self):
print('sing a song')
# def __getattribute__(self, item):
# #在方法中使用object来获取属性值
# res=object.__getattribute__(self,item)#获取类成员必须要使用这种格式
# return res
def __getattr__(self, item):
return False
p1=Person('lisi',11,'female')
print(p1.name)#lisi,访问存在的成员
print(p1.home)#False。访问不存在的成员反馈回来的内容
3、setattr
- 当给对象的成员进行赋值操作的时候会自动触发,包括添加,修改
- 可以限制或管理对象成员的添加和修改操作
- 接受三个参数1,一个self参数,接受当前对象,2,设置的成员名,3成员属性的值
- 无返回值
- 在当前的魔术方法中禁止给当前对象的成员直接进行赋值操作,会触发递归
- 如果需要赋值操作,需要借助object。使用object.__setattr(self,item,value)
class Person():
name='name'
age=34
gender='male'
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def say(self):
print('talk somthing')
def sing(self):
print('sing a song')
# def __getattribute__(self, item):
# #在方法中使用object来获取属性值
# res=object.__getattribute__(self,item)#获取类成员必须要使用这种格式
# return res
def __getattr__(self, item):
return False
def __setattr__(self, key, value):
print(self,key,value)
p1=Person('lisi',11,'female')
print(p1.name)#lisi,访问存在的成员
print(p1.home)#False。访问不存在的成员反馈回来的内容
p1.world='hello'#<__main__.Person object at 0x000001987654B460> world hello
4、delattr
- 当删除对象成员时自动触发
- 可以限制对象成员的删除,还可以删除不存在成员时防止报错
- 参数有伞,1、self接收当前对象,2,、item删除的成员名称
- 无返回值
- 在当前魔术方法中禁止直接删除对象的成员,会触发递归操作
- 如果想要删除当前对象的成员需要借助object。格式为object.delattr(self,item)
class Person():
name='name'
age=34
gender='male'
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def say(self):
print('talk somthing')
def sing(self):
print('sing a song')
def __del__(self,item):
print(item)
object.__delattr__(self,item)
p1=Person('lisi',11,'female')
del p1.name
print(p1.name)#报错
访问成员的顺序
1、调用__getattribute__
2、调用数据描述符
3、调用当前对象的成员
4、调用当前类的的成员
5、调用非数据描述符
6、调用父类的成员
7、调用__getattr__魔术方法
8、描述符类似于java的getter,setter
- 其实就是一个类
- 当一个类,包含了仨个魔术方法(get , set,delete,)或之一的,那么这个类就称之为描述符类
- 描述符的作用就是对一个类中的某个成员进行一个详细的管理操作(获取,修改,删除)
- 描述符就是代理了一个类中的成员的操作,描述符属于类,只能定义为类的属性
- 一个类成员的值,是另一个描述符类的对象,那么当对这个类中的成员进行操作时,可以理解为是对另一个对象的操作(关联过去的)
# 定义一个描述符类
class PersonName():
__name = 'zhangsan'
def __get__(self, instance, owner):
print(self)
print(instance)
print(owner)
return self.__name
def __set__(self, instance, value):
self.__name=value
def __delete__(self, instance):
#del self.__name
print('不允许删除')
class Person():
name = PersonName()
p1 = Person()
print(p1.name)#实际打印的是PersonName(先Person,后关联到PersonName)
#打印出<__main__.PersonName object at 0x00000287F882B460>
#打印出<__main__.Person object at 0x00000287F8839400>
#打印出<class '__main__.Person'>
#打印出zhangsan
p1.name='lisi'
print(p1.name)#lisi
9、描述符案例
使用传统方法,初始化方法中实现
#要求学员分数只能在1-100范围内
#方法1,在init函数中做判断
class Student():
def __init__(self,id,name,score):
self.id = id
self.name = name
#self.score = score
if score<100 and score>0:
self.score = score
else:
print('分数不符合要求')
def returnMe(self):
info= f'''
学员编号:{self.id}
学员姓名:{self.name}
学员分数:{self.score}
'''
print(info)
s1=Student('001','zhagnsan',99)
s1.returnMe()#打印出学员信息
使用setattr魔术方法
# 要求学员分数只能在1-100范围内
# 方法1,在init函数中做判断
class Student():
def __init__(self, id, name, score):
self.id = id
self.name = name
self.score = score
def __setattr__(self, key, value):
if key == 'score':
if value < 100 and value > 0:
object.__setattr__(self, key, value)
else:
print('当前分数不符合要求')
else:
object.__setattr__(self, key, value)
def returnMe(self):
info = f'''
学员编号:{self.id}
学员姓名:{self.name}
学员分数:{self.score}
'''
print(info)
s1 = Student('001', 'zhagnsan', 99)
s1.returnMe() # 打印出学员信息
s1.score=-34#当前分数不符合要求
s1.returnMe()
使用描述符代理分数属性
- 定义Score描述符类
- 把学生类中的score这个成员交给描述符类进行代理
- 只要在代理的描述符类对分数进行赋值和获取
# 要求学员分数只能在1-100范围内
# 定义Score类代理分数操作
class Score():
__score = None
def __get__(self, instance, owner):
return self.__score
def __set__(self, instance, value):
if value > 0 and value < 100:
self.__score = value
else:
print('分数输入错误')
def __delete__(self, instance, owner):
pass
class Student():
score=Score()
def __init__(self, id, name, score):
self.id = id
self.name = name
self.score = score
def returnMe(self):
info = f'''
学员编号:{self.id}
学员姓名:{self.name}
学员分数:{self.score}
'''
print(info)
s1 = Student('001', 'zhagnsan', 99)
s1.returnMe() # 打印出学员信息
s1.score=-33#分数输入错误
s1.score=34
s1.returnMe()#34
10、描述符三种定义方式
数据描述符:(完整)
同时具备三个魔术方法的类就是数据描述符
非数据描述符(不完整)
没有同时具备三个魔术方法
三种定义方式
- 1、通过定义描述符类来实现
class ScoreManage():
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
class Student():
score=ScoreManage()
- 2、使用property函数来实现
在当前需要被管理的类中,直接定义类似下面的三个方法
class Student():
#在函数中以参数的形式指定对应的方法
def getScore(self):
print('getScore')
def setScore(self,value):
print('setScore',value)
def delScore (self):
print('delScore')
#在property函数中指定对应的三个方法,第一个方法对应__get__,第2个方法对应__set__,第3个方法对应__delete__
score=property(getScore,setScore,delScore)
s1=Student()
print(s1.score)#getScore,None
s1.score=200#setScore 200
del s1.score#delScore
- 3、使用装饰器语法@property来实现
class Student():
__score = None
@property
def score(self):
print('get')
return self.__score
@score.setter
def score(self, value):
print('set')
self.__score = value
@score.deleter
def score(self):
print('delete')
del self.__score
s1=Student()
print(s1.score)
s1.score=33
print(s1.score)
del s1.score
11、设计模式–单例模式
为了完成某个功能或需求,根据经验和总结,对实现的代码步骤和代码设计进行的总结和归纳,形成的经典模式
设计模式在python中并不重要
同一个类只能创建一个对象去使用。
如何设计单例呢?
- 1、需要有一个方法可以控制当前对象的创建
构造方法__new__
- 2、在这个方法中,需要存储一个标识,去检测是否有对象
构造方法中加判断条件
创建一个属性,进行存储,默认值为None
- 3、在创建对象的方法中,去检测和判断是否有对象
如果没有对象,则创建对象,并且把对象存储起来
如果存储的事对象,则直接返回对象,就不需要创建新的对象了
class Demo():
# 1、定义私有属性存储对象,默认为None
__obj = None
# 2、定义构造方法
def __new__(cls, *args, **kwargs):
pass
# 3、在创建对象的过程中,判断是否有对象
if cls.__obj:
# 说明有对象
return cls.__obj
else:
# 如果没有对象,则创建对象
obj = object.__new__(cls)
# 并存储起来
cls.__obj = obj
# 在返回对象
return cls.__obj
a=Demo()#<__main__.Demo object at 0x000002A273FC9400>
b=Demo()#<__main__.Demo object at 0x000002A273FC9400>
print(a,b)#返回的是同一个实例
12、设计模式–Mixin模式(混合设计模式)
- python支持多继承
- 继承需要有一个必要的前提,继承应该是一个‘is-a’的关系
- is-a就是说某个实例是另一个类的所属,is-a就是要拒绝多继承
- 解决方案就是,给其中一个需要继承的类,定义为一个mixin混合类
Mixin表示混入(mix-in)
- Mixin必须是表示一种功能,而不是一个对象
- Mixin的功能必须单一,如果有多个功能,那就多定义Mixin类
- python的Mixin是通过多继承实现的
- Mixin这个类通常不单独使用,而是混合到其他类中,去增加功能
- Mixin类不依赖子类的实现,即便子类没有继承这个Mixin,子类也能正常地运行,可能就是缺少了一些功能而已。
使用Mixin混入类的好处
- 1、Mixin这个混入类的设计模式,在不对类的内容修改的前提下,扩展了类的功能
- 2、Mixin呼入类为了提高代码的重用性,使代码的结构更加的简单清晰
- 3、可以根据开发需求任意调整功能(创建新的Mixin混入类)
- 4、避免设计多层次的复杂的继承关系
#交通工具类
class vehicle():
#运货
def carry(self):
print('运输货物')
#载客
def take(self):
print('搭载乘客')
#飞行器类 ,定义为Mixin混合类(这里仅仅是名称上做了个区别) ,此时等于把飞行器这个类,作为了一个扩展的功能,来实现多个类
class aircraftMixin():
def fly(self):
print('可以起飞了')
#汽车类
class Car(vehicle):
pass
#定义飞机类
class airplane(vehicle,aircraftMixin):
pass
#直升机类
class helicopter(vehicle,aircraftMixin):
pass
13、设计模式–抽象类
- 抽象类是一个特殊的类(和java的抽象类概念相似)
- 不能直接使用,不能直接实例化为一个对象
- 抽象类中包含了抽象方法,抽象方法没有实现代码
- 抽象类需要子类继承,并重写父类的方法才可以使用
- 需要导入abc模块import abc。并且类的metaclass属性必须是abc.ABCMeta
- 抽象方法必须使用抽象装饰符@abc.abstractclassmethod进行装饰
# 导入抽象模块
import abc
#定义抽象类
class WriteCode(metaclass=abc.ABCMeta): # 类的metaclass属性必须是abc.ABCMeta
# 定义需要的抽象方法,要使用装饰器进行装饰
@abc.abstractclassmethod
def write_php(self):
pass
def write_java(self):
print('直接实现,子类不重写')
def write_python(self):
print('也可以不抽象直接实现')
#定义子类,继承抽象类,并实行抽象类的抽象方法
class RealWrite(WriteCode):
def write_php(self):
print('write php code')
def write_python(self):
print('write python code')
w1=RealWrite()#报错,抽象类不能实例化对象
w1.write_java()#直接实现,子类不重写
w1.write_php()#write php code
w1.write_python()#write python code
标签:__,name,魔术,对象,self,面向对象,描述符,print,def 来源: https://blog.csdn.net/weixin_43745804/article/details/120383369