Python(IT峰)笔记11-面向对象高阶,内置成员,方法的分类,面向对象的常用函数,魔术方法,str和repr的区别,成员相关魔术方法,描述符,描述符三种定义方式,单例模式,MixIn模式,抽象类

2021/9/20 17:27:32

本文主要是介绍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


这篇关于Python(IT峰)笔记11-面向对象高阶,内置成员,方法的分类,面向对象的常用函数,魔术方法,str和repr的区别,成员相关魔术方法,描述符,描述符三种定义方式,单例模式,MixIn模式,抽象类的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程