day16-面向对象基础(三)
今日摘要
今天主要整理一下这俩天学习的内容,面向对象也快学完了,深刻的认识到面向对象就是一个思想,怎么把思想理解了,其他也就不是什么事了
1.类的约束
2.类的类方法与静态方法
3.类的反射
4.类的内置方法以及双下方法
开始今日份总结
1.类的约束
类的约束,就是对类进行一些正确的引导,约束,统一规范,满足正确的开发方式
1.1类的约束的第一种方式
class A: def pay(self,money):#规定都必须有pay方法 raise Exception('未定义指定函数') class Alipay(A): def pay(self,money): print('本次消费%s'%money) class JDpay(A): def pay(self,money): print('本次消费%s'%money) class Wechatpay(A): def zhifu(self,money): print('本次消费%s'%money) w1 = Wechatpay() def pay(obj,money):#约束一下,约定所有人的支付必须是使用统一的接口,但是这样也没又很强烈的约束功能 obj.pay(money) pay(w1,100) #这种事如果没有定义指定的方法会抛出错误
1.2类的约束的第二种方式
from abc import ABCMeta,abstractmethod class A(metaclass=ABCMeta): def pay(self,money): print('请创建正确的方法') @abstractmethod class Alipay(A): def pay(self,money): print('本次消费%s'%money) class JDpay(A): # def zhifu(self,money): # print('本次消费%s'%money) def pay(self, money): print('此次消费%s' % money) def pay(obj,money): obj.pay(money) j1 = JDpay() pay(j1,100) #第二种方式就是调用abc模块,但是这种在日常使用中,很少用到,一般都是用第一种。
2.绑定方法与非绑定方法
在类内部一般包含俩种方法,一种为绑定方法,一种为非绑定方法
2.1绑定方法
绑定方法:绑定给谁,就由谁来执行,谁用就会把调用者当做第一个方法传入
绑定给对象的方法:类内没有被任何装饰器修饰的方法
绑定给类的方法:类内定义的装饰器装饰的classmethod修饰的方法
看了一圈以及源码对于怎么用,或者是使用场景都没有说,真的是一头雾水,写一点自己能理解的把
#原本 class Test_time(): def __init__(self,year,month,day): self.year = year self.month = month self.day = day def out_data(self): print('现在日期为{}年{}月{}日'.format(self.year,self.month,self.day)) t1 = Test_time(2018,12,28) t1.out_data() 如果传入数据为不是正确的数据,例如‘2018-12-28’,就需要其他函数对数据进行整理 class Test_time(): def __init__(self,year,month,day): self.year = year self.month = month self.day = day def out_data(self): print('现在日期为{}年{}月{}日'.format(self.year,self.month,self.day)) @classmethod def data_solite(cls,msg): year, month, day = map(int, msg.split('-')) ret = cls(year,month,day) return ret msg ='2018-12-28' t2 =Test_time.data_solite(msg) t2.out_data()
这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符
在我的理解中,类方法就是将一个类在没有实例化对象之前调用类里面的方法,或者是先行修改内容,这样就不需要修改构造函数,相当于重置构造函数。
2.2非绑定方法
没有自动传值这么一个说法,就是一个普通函数,一个普通的工具,对于对象和类都可以调用。不与类或者对象进行绑定
就是在方法上加@staticmethod
import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime()) t = TimeTest(2, 10, 10) nowTime = t.showTime() print(nowTime) #类与对象都可以调用,使用对应的方法
3.类的反射
类的反射也是类的内置方法,也是一个特别重要的点
3.1 hasattr 判断对象或者类是否存在指定的属性,看代码以及结果
class people: def __init__(self,name,age): self.name = name self.age = age def talk(self): print("%s is talking."%self.name) p1 = people('alex',18) print(hasattr(p1,'name')) print(hasattr(p1,'sex')) 结果 True False
hasattr判断完成后,会返回一个布尔值,有就返回True,无就返回False
3.2getattr 获取到一个对象或者类的属性,加()就是执行,看代码
class people: def __init__(self,name,age): self.name = name self.age = age def talk(self): print("%s is talking."%self.name) p1 = people('alex',18) print(getattr(p1,'name')) print(getattr(p1,'sex','man')) print(getattr(p1,'sex')) 结果 alex man File "D:/PycharmProjects/s2018/day6/test.py", line 13, in <module> print(getattr(p1,'sex')) AttributeError: 'people' object has no attribute 'sex'
对于getattr,如果对象或者是类有输入的属性,则,返回正确属性。无则报错,如果我们指定默认值,则返回默认值,在看一下其他
class people: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def talk(self): print("%s is talking."%self.name) p1 = people('alex',18,'woman') getattr(p1,'talk')()#getattr获取到方法后加()就是执行 print(getattr(p1,'sex','man'))#类内如果对属性已经确认过,显示对象已经确认的值,而不显示默认值 结果 alex is talking. woman
3.3setattr 是修改已有的属性或者是新加一个属性,看代码
class people: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def talk(self): print("%s is talking."%self.name) p1 = people('alex',18,'woman') print('修改前',p1.age) setattr(p1,'age',20) print('修改后',p1.age) setattr(p1,'country','China') print(p1.__dict__) 结果 修改前 18 修改后 20 {'country': 'China', 'name': 'alex', 'sex': 'woman', 'age': 20}
3.4delattr就是对现有的对象或者类的属性就行删除,这个比较简单,看代码
class people: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def talk(self): print("%s is talking."%self.name) p1 = people('alex',18,'woman') print('修改前',p1.__dict__) delattr(p1,'name') print('修改后',p1.__dict__) 结果 修改前 {'age': 18, 'name': 'alex', 'sex': 'woman'} 修改后 {'age': 18, 'sex': 'woman'}
3.5类的反射其他用法
在说一下在类的反射中其他用法
#可以用于反射的方面有实例化对象, 类,其他py文件 本py文件 # 1.操作类的角度 class A: country = 'China' area = '深圳' def __init__(self,name,age): self.name = name self.age = age def func(self): print(666) print(getattr(A,'country')) print(getattr(A,'area')) print(getattr(A,'name')) getattr(A,'func')(23) print(hasattr(A,'func2')) # 2.其他py文件(模块) # 不用反射之前: import attr print(attr.flag) ret = attr.func # print(ret(10)) print(attr.B.name_list) obj = attr.B('barry','男') # print(obj.name_list) print(obj.name) ret = 'B' # 用反射的方法: import attr print(getattr(attr,'flag')) # 1,找到func 并执行 ret = getattr(attr,'func') print(ret(10)) #2,找到B类并调用 name_list func函数 b = getattr(attr,'B') print(b.name_list) print(getattr(attr.B,'name_list')) getattr(attr.B,'func')(1) #3,找到B类实例化对象在找 name,name_list func函数 b = getattr(attr,'B') obj = b('alex','男') print(obj.name) print(obj.name_list) # 4,本模块的反射 import sys obj = sys.modules[__name__] print(obj) def func(): print(666) ret = input('>>>') # ret() getattr(obj,ret)() def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') l1 = [func1,func2,func3] for i in l1: i() import sys obj = sys.modules[__name__] l1 = ['func%s' % i for i in range(1,4)] # print(l1) for i in l1: getattr(obj,i)()
到底什么对象可以反射
- 实例化对象
- 类
- 其他模块
- 本模块(对于本模块,需要创建sys文件进行设定,如果本模块中包含模块则不需要)
4.类的内置方法以及双下方法
类的内置方法其实包含类的反射中四个方法,上面已经写了就不在描述
4.1其他内置方法
# isinstance 判断此对象是不是该类(或者是该类的子类)实例化的对象 class A: pass class B(A): pass obj = B() s1 = 'afds' print(isinstance(obj,B)) #True print(isinstance(obj,A)) #True print(isinstance(s1,str)) #True # issubclass 判断的是此类是不是后面类的派生类 class D: pass class A(D): pass class B(A): pass abj = B() print(issubclass(B,A)) #True print(issubclass(B,D)) #True
4.2双下方法
# 特殊双下方法 # __init__ # len # s1 = 'fdsafdsa' # l1 = [1,2,3] # dic = {'name':'alex','age': 12} # i = 12 # # print(len(s1)) # int # # print(len(l1)) # list # print(len(dic)) # print(len(i)) # # class A: # # def __init__(self,name,age): # # self.name = name # # self.age = age # # self.sex = '男' # # # # def __len__(self): # # # print(666) # # return len(self.__dict__) # # a = A('barry', 18) # # # len(a) # len(对象) 如果此类中有__len__ 就_方法会自动执行__len_ # # print(len(a)) # print(hash('fsdaf')) # class A: # def __init__(self,name,age): # self.name = name # self.age = age # self.sex = '男' # # def __len__(self): # # print(666) # return len(self.__dict__) # # def __hash__(self): # return 1 # def __str__(self): # print(555) # return 'fdsaf' # object # a = A('barry', 18) # print(hash(a)) # print(a) # 对一个对象打印时,自动触发类中的__str__方法 # print(a,type(a)) # __call__方法 # class Foo: # # def __init__(self): # print(11) # # def __call__(self, *args, **kwargs): # pass # obj = Foo() # obj() # 对象() 触发 __call__方法 # __new__ 构造方法 # class A: # def __init__(self,name): # self.name = name # print('in A __init__') # object # obj = A('alex') # object # class A: # def __init__(self,name): # self.name = name # print('in A __init__') # def __new__(cls, *args, **kwargs): # print('in A __new__') # return object.__new__(cls) # # a = A('春哥') # print(a.name) # 1, 类名() 执行object.__new__方法,开辟的对象空间并返回 # 2,自动执行__init__方法,将空间创给self # 3,在__init__给对象封装属性。
__call__的三件事
- 先造一个空对象obj:obj = object.__new__(self)
- 初始化obj:self.__init__(obj,*args,**kwargs)
- 返回obj:return obj
单例模式,比较重要!
class A: __instance = None def __init__(self,name,age): self.name =name self.age = age def __new__(cls, *args, **kwargs): if cls.__instance is None: obj = object.__new__(cls) cls.__instance = obj return cls.__instance ret1 = A('alex',123) ret2 = A('wusir',22) ret3 = A('barry',18) print(ret1) print(ret2) print(ret3) #结果 <__main__.A object at 0x01702470> <__main__.A object at 0x01702470> <__main__.A object at 0x01702470> #就会发现单例模式就是无论怎么实例化,生成的都是同一个,这样节省名称空间