Python面向对象之反射、元类
作者:互联网
一、反射
反射指的是一个对象应该具备,可以增、删、改、查属性的能力,通过字符串来操作属性。涉及四个函数,这四个函数就是普通的内置函数,没有下划线,但实现的功能和原理基本一致
hasattr(object,name) # 判断对象是否实现某个属性,返回值是bool类型 setattr(object,name,value) # 为对象增加新的属性 getattr(object,name,default) # 从对象中获取某个属性,返回值是str类型 delattr(object,) # 从对象中删除某个属性,无返回值
class Person: def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender p=Person("aaa",20,"woman") # print(p.name) print(hasattr(p,"name")) # 判断是否是类的属性 True if hasattr(p,"name"): print("我有name") print(getattr(p,"name",None)) #从对象中取出属性,第三个值位默认值 aaa # 当属性不存在是返回默认值 # 为对象添加新的属性 a = setattr(p,"id","1234") print(a) # 从对象中删除对象 c = delattr(p,"id") print(c)
反射使用:
1、一个类在定义的时候,可能一些属性的设计并不是很完美,而后期需要作出修改过或删除操作属性时,使用反射可以不需要修改源代码。反射其实就是对属性的增删改查,但如果直接使用内置的__dict__来操作,语法繁琐不便操作。
2、另一个就是调用另一方提供的对象时,必须先判断这个对象是否满足需求,也就是判断是否是我们需要的属性和方法。动态添加模块功能。框架就与代码实现了彻底的耦合
二、元类 metaclass
元类是创建类的类 所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化)。元类即 用于产生类的类。默认情况下所有类的元类都是type
1、编写元类:
只需要声明一个继承自type的类(使用class关键字)
类只是对象,元类也只是类。元类的行为继承自type;因此任何type的子类都可以作为元类
实例:例如控制类的名字必须以大驼峰体的方式来书写。用初始化的方法 我们只要找到类对象的类(元类),覆盖其中__ init__方法就能实现需求。不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖__init__来完成需求。
# 定义一个元类 class MyType(type): def __init__(self,clss_name,bases,dict): #继承后用super调用 super().__init__(clss_name,bases,dict) print(clss_name,bases,dict) if not clss_name.istitle(): raise Exception("类名写错了~") class pig (metaclass=MyType): print("绑定了元类~") class Duck(metaclass=MyType): print("规定的协议要遵守~") MyType("pig",(),{})
2、元类中的__call__方法
当调用类对象时会自动执行元类中的__call__方法,并将这个类本身作为第一个参数传入,以及后面的数,覆盖元类中的__call__之后,这个类无法产生对象,必须调用super().__call__来完成对象的创建,并返回其返回值。
#实现将对象的所有属性名称转化为大写 class MyType(type): def __call__(self, *args, **kwargs): new_arg = [] # 要求的书写规范 for a in kwargs: new_arg.append(a.upper()) # 转换为大写 print(new_arg) #print(kwargs) return super().__call__(*new_arg) class Person(metaclass=MyType): def __init__(self,name,gender): self.name=name self.gender=gender p=Person(name="aaa",gender="man") print(p.gender) print(p.name) ''' ['NAME', 'GENDER'] GENDER NAME '''
3、__new__方法
创建类的对象时,会先执行元类中的__new__ 方法。执行了__new__
函数,就不会再执行__init__
,因为__new__
函数是真正用于创建类的方法,只有创建类成功了才会执行__init__函数,__new__必须要有返回值且返回值类型为__type__
时才会执行__init__
函数,
class Meta(type): def __new__(cls, *args, **kwargs): print(cls) # 元类自己 print(args) # 创建类需要的几个参数 类名,基类,名称空间 print(kwargs) #空的 print("new run") # return super().__new__(cls,*args,**kwargs) obj = type.__new__(cls,*args,**kwargs) print(obj) #<class '__main__.A'> return obj #无返回值,不执行init方法 def __init__(self,a,b,c): super().__init__(a,b,c) print("init run") #有返回值就执行init run class A(metaclass=Meta): pass print(A) #此时有返回值执行init方法,就执行这个 ''' <class '__main__.Meta'> ('A', (), {'__module__': '__main__', '__qualname__': 'A'}) {} new run init run <class '__main__.A'> '''
4、单例
单例是指的是单个实例,指一个类只能有一个实例对象。为了节省资源,当两个对象的数据完全相同时 则没有必要占用两份资源。
# 单例n元类 class Single(type): def __call__(self, *args, **kwargs): if hasattr(self,"obj"): #判断是否存在已经有的对象 return getattr(self,"obj") # 有就返回 obj = super().__call__(*args,**kwargs) # 没有则创建 print("这下有了") self.obj = obj # 并存入类中 return obj class Student(metaclass=Single): def __init__(self,name): self.name = name class Person(metaclass=Single): pass # 只会创建一个对象 Person() Person()
四、冒泡算法:冒泡排序
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
def bubbleSort(arr): n = len(arr) # 遍历所有数组元素 for i in range(n): print(i) for j in range(0, n - i - 1): if arr[j] > arr[j + 1]: arr[j], arr[j + 1] = arr[j + 1], arr[j] arr = [64, 34, 25, 12, 22, 11, 90] #即用64与34比较,交换二者位置,再与25比较又交换位置,以此类推 bubbleSort(arr) print("排序后的数组:") for i in range(len(arr)): print("%d" % arr[i])
标签:__,name,Python,self,元类,面向对象,init,print 来源: https://www.cnblogs.com/wmtly/p/16081110.html