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

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、对象方法:

2、类方法
在类中定义的方法,使用类装饰器@classmethod进行了装饰
方法中有cls这个形参
不需要实例化对象,直接使用类进行调用
会把调用这个方法的类传递进来
3、绑定类方法

4、静态方法(和java的静态方法还是有很多不同的)

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、面向对象的常用函数

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__构造方法

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__

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

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

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

2、getattr

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

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

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

# 定义一个描述符类
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()

使用描述符代理分数属性

# 要求学员分数只能在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、描述符三种定义方式

数据描述符:(完整)
同时具备三个魔术方法的类就是数据描述符

非数据描述符(不完整)
没有同时具备三个魔术方法

三种定义方式

class ScoreManage():
	def __get__(self, instance, owner):
		pass
	def __set__(self, instance, value):
		pass
	def __delete__(self, instance):
		pass

class Student():
	score=ScoreManage()
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
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中并不重要

同一个类只能创建一个对象去使用。
如何设计单例呢?

构造方法__new__

构造方法中加判断条件
创建一个属性,进行存储,默认值为None

如果没有对象,则创建对象,并且把对象存储起来
如果存储的事对象,则直接返回对象,就不需要创建新的对象了

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模式(混合设计模式)

Mixin表示混入(mix-in)

使用Mixin混入类的好处

#交通工具类
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、设计模式–抽象类

# 导入抽象模块
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