class Bar: def __init__(self, name, age): self.name = name self.age = age # def __str__(self): # print("this str") # return "名字是%s age%s" % (self.name, self.age) def __repr__(self): # 转换字符串,在解释器中执行 print("thsi repr") return "%s" % self.name test = Bar("alex", 18) print(test) #__str__定义在类内部,必须返回一个字符串类型, #__repr__定义在类内部,必须返回一个字符串类型, #打印由这个类产生的对象时,会触发执行__str__,若是没有__str__会触发__repr__
class Bar: pass class Foo(Bar): pass obj=Foo() print(isinstance(obj,Foo)) print(Foo.__bases__) print(issubclass(Foo,Bar)) """ True (<class '__main__.Bar'>,) True """
class Foo: def __init__(self,x): self.name=x def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): #这的key类型是str print('----> from setattr') # if not isinstance(value,str): # raise TypeError('must be str') #setattr(self,key,value)和 self.key=value #这就无限递归了,你好好想一想 self.__dict__[key]=value def __delattr__(self, item): #这的item类型是str print('----> from delattr') # delattr(self,item)和 del self.item #这就无限递归了 self.__dict__.pop(item) # __setattr__添加/修改属性会触发它的执行 f1 = Foo('alex') #设置属性 触发__setattr__ print(f1.__dict__) # 由于你重写了__setattr__,凡是赋值操做都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操做属性字典,不然永远没法赋值 f1.z = 3 # 添加属性 触发__setattr__ print(f1.__dict__) setattr(f1,'nn',55) #添加属性 触发__setattr__ print(f1.__dict__) f1.__dict__['a'] = 3 # 能够直接修改属性字典,来完成添加/修改属性的操做,这样的操做不触发__setattr__ print(f1.__dict__) # __delattr__删除属性的时候会触发 del f1.a #触发__delattr__ print(f1.__dict__) delattr(f1,'nn') #触发__delattr__ print(f1.__dict__) f1.__dict__.pop('z') #不触发__delattr__ print(f1.__dict__) # __getattr__只有在使用点调用属性且属性不存在的时候才会触发 f1.xxxxxx
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('执行的是我') # return self.__dict__[item] f1=Foo(10) print(f1.x) f1.xxxxxx #不存在的属性访问,触发__getattr__ """ 10 执行的是我 """ class Foo: def __init__(self,x): self.x=x def __getattribute__(self, item): print('无论是否存在,我都会执行') f1=Foo(10) f1.x f1.xxxxxx """ 无论是否存在,我都会执行 无论是否存在,我都会执行 """ class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('执行的是我') # return self.__dict__[item] def __getattribute__(self, item): print('无论是否存在,我都会执行') raise AttributeError('哈哈') f1=Foo(10) f1.x f1.xxxxxx """ 无论是否存在,我都会执行 执行的是我 无论是否存在,我都会执行 执行的是我 """
包装:python为你们提供了标准数据类型,以及丰富的内置方法,其实在不少场景下咱们都须要基于标准数据类型来定制咱们本身的数据类型,新增/改写方法,这就用到了咱们刚学的继承/派生知识(其余的标准类型都可以经过下面的方式进行二次加工)javascript
class List(list): #继承list全部的属性,也能够派生出本身新的,好比append和mid def append(self, p_object): ' 派生本身的append:加上类型检查' if not isinstance(p_object,int): raise TypeError('must be int') super().append(p_object) @property def mid(self): '新增本身的属性' index=len(self)//2 return self[index] l=List([1,2,3,4]) print(l) l.append(5) print(l) # l.append('1111111') #报错,必须为int类型 print(l.mid) #其他的方法都继承list的 l.insert(0,-123) print(l) l.clear() print(l)
受权:受权是包装的一个特性, 包装一个类型一般是对已存在的类型的一些定制,这种作法能够新建,修改或删除原有产品的功能。其它的则保持原样。受权的过程,便是全部更新的功能都是由新类的某部分来处理,但已存在的功能就受权给对象的默认属性。 实现受权的关键点就是覆盖__getattr__方法java
import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): self.file=open(filename,mode,encoding=encoding) def write(self,line): t=time.strftime('%Y-%m-%d %T') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): return getattr(self.file,item) f1=FileHandle('b.txt','w+') f1.write('你好啊') f1.seek(0) print(f1.read()) f1.close()
class List: def __init__(self,x): self.seq=list(x) def append(self,value): if not isinstance(value,str): raise TypeError('must be str') self.seq.append(value) @property def mid(self): index=len(self.seq)//2 return self.seq[index] def __getattr__(self, item): return getattr(self.seq,item) def __str__(self): return str(self.seq) l=List([1,2,3]) l.append('1') print(l.mid) l.insert(0,123123123123123123123123123) # print(l.seq) print(l)
class Foo: def __init__(self,name): self.name=name # 参数类型是字符串 def __getitem__(self, item): print('getitem',type(item)) print(self.__dict__[item]) def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setitem__(self, key, value): print('setitem',type(key)) self.__dict__[key]=value def __setattr__(self, key, value): print('----> from setattr',type(key)) self.__dict__[key] = value def __delitem__(self, key): print('del obj[key]时,我执行',type(key)) self.__dict__.pop(key) def __delattr__(self, item): print('----> from delattr del obj.key时,我执行',type(item)) self.__dict__.pop(item) #触发__setattr__ f1=Foo('sb') f1.gender='male' setattr(f1,'level','high') #触发__setitem__ f1['age']=18 f1['age1']=19 #触发__delattr__ del f1.age1 delattr(f1,'level') #触发__delitem__ del f1['age'] #触发__getattr__ f1.xxxxxx #触发__getitem__ f1['name'] #什么都不触发 f1.__dict__['test']='aa' f1.__dict__['test'] f1.__dict__.pop('test') print(f1.__dict__)
# 和生成实例化对象的内容相对应 date_dic={ 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}/{0.month}/{0.year}', 'mdy':'{0.month}-{0.day}-{0.year}', } class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __format__(self, format_spec): # format_spec指定格式化的类型 if not format_spec or format_spec not in date_dic: format_spec='ymd' fmt=date_dic[format_spec] # 经过date_dic字典格式化成相应格式的类型 return fmt.format(self) #把对象传入,格式化的内容 d1=Date(2016,12,29) print(format(d1)) print('{:mdy}'.format(d1)) """ 2016-12-26 20161226 """
class Poo: __slots__ = 'x' p1 = Poo() p1.x = 1 # p1.y = 2 # 报错 print(p1.__slots__) #打印x p1再也不有__dict__ class Bar: __slots__ = ['x', 'y'] n = Bar() n.x, n.y = 1, 2 # n.z = 3 # 报错 print(n.__slots__) #打印['x', 'y'] class Foo: __slots__=['name','age'] f1=Foo() f1.name='alex' f1.age=18 print(f1.__slots__) #['name', 'age'] f2=Foo() f2.name='egon' f2.age=19 print(f2.__slots__) #['name', 'age'] print(Foo.__dict__)#f1与f2都没有属性字典__dict__了,统一归__slots__管,节省内存 """ { 'age': <member 'age' of 'Foo' objects>, 'name': <member 'name' of 'Foo' objects>, '__module__': '__main__', '__doc__': None, '__slots__': ['name', 'age']}ame', 'age'] } """
class Foo: def __init__(self,start,stop): self.num=start self.stop=stop def __iter__(self): return self def __next__(self): if self.num >= self.stop: raise StopIteration n=self.num self.num+=1 return n f=Foo(1,5) from collections import Iterable,Iterator print(isinstance(f,Iterator)) for i in Foo(1,5): print(i) """ True 1 2 3 4 """
class Range: def __init__(self,start,end,step): self.start=start self.end=end self.step=step def __next__(self): if self.start >= self.end: raise StopIteration x=self.start self.start+=self.step return x def __iter__(self): return self for i in Range(1,7,2): print(i) #1 3 5
class Fib: def __init__(self): self._a=0 self._b=1 def __iter__(self): return self def __next__(self): self._a,self._b=self._b,self._a + self._b return self._a f1=Fib() print(f1.__next__()) print(next(f1)) print(next(f1)) for i in f1: if i > 100: break print('%s ' %i,end='') ''' 1 1 2 3 5 8 13 21 34 55 89 '''
class Foo: #我是描述信息 pass class Bar(Foo): pass print(Bar.__doc__) #None 该属性没法继承给子类
#test.py class C: def __init__(self): self.name = '测试' #aa.py from test import C class Foo: pass f1 = Foo() print(f1.__module__) #__main__ print(f1.__class__) #<class '__main__.Foo'> c1 = C() print(c1.__module__) #test 即:输出模块 print(c1.__class__) #<class 'test.C'> 即:输出类
class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->') """ 执行我啦 -------> """ class Foo: def __del__(self): print('执行我啦') f1=Foo() # del f1 print('------->') """ -------> 执行我啦 """
""" 典型的应用场景: 建立数据库类,用该类实例化出数据库连接对象,对象自己是存放于用户空间内存中,而连接则是由操做系统管理的,存放于内核空间内存中 当程序结束时,python只会回收本身的内存空间,即用户态内存,而操做系统的资源则没有被回收,这就须要咱们定制__del__, 在对象被删除前向操做系统发起关闭数据库连接的系统调用,回收资源 这与文件处理是一个道理: f=open('a.txt') #作了两件事,在用户空间拿到一个f变量,在操做系统内核空间打开一个文件 del f #只回收用户空间的f,操做系统的文件还处于打开状态 #因此咱们应该在del f以前保证f.close()执行,即使是没有del,程序执行完毕也会自动del清理资源,因而文件操做的正确用法应该是 f=open('a.txt') #读写... f.close() #不少状况下你们都容易忽略f.close,这就用到了with上下文管理 """ import time class Open: def __init__(self,filepath,mode='r',encode='utf-8'): self.f=open(filepath,mode=mode,encoding=encode) def write(self): pass def __getattr__(self, item): return getattr(self.f,item) def __del__(self): print('----->del') self.f.close() ## f=Open('a.txt','w') f1=f del f #f1=f 引用计数不为零 print('=========>') """ =========> ----->del """
""" with open('a.txt') as f: '代码块' 上述叫作上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法 __exit__的运行完毕就表明了整个with语句的执行完毕 """ class Open: def __init__(self,name): self.name=name def __enter__(self): print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') return self def __exit__(self, exc_type, exc_val, exc_tb): print('with中代码块执行完毕时执行我啊') with Open('a.txt') as f: print('=====>执行代码块') # print(f,f.name) #__enter__方法的返回值赋值给as声明的变量 """ 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 =====>执行代码块 with中代码块执行完毕时执行我啊 """ #__exit__()中的三个参数分别表明异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都没法执行 class Open: def __init__(self,name): self.name=name def __enter__(self): print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb): print('with中代码块执行完毕时执行我啊') print(exc_type) print(exc_val) print(exc_tb) with Open('a.txt') as f: print('=====>执行代码块') raise AttributeError('***着火啦,救火啊***') #遇到raise,with里代码就结束,with代码块里raise后面的代码就不会执行,with代码结束就会执行__exit__方法 print('11111111') ####永远不会打印 print('0'*100) #------------------------------->不会执行 #若是__exit()返回值为True,那么异常会被清空,就好像啥都没发生同样,with后的语句正常执行 class Open: def __init__(self,name): self.name=name def __enter__(self): print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb): print('with中代码块执行完毕时执行我啊') print(exc_type) print(exc_val) print(exc_tb) return True #有返回值 with Open('a.txt') as f: print('=====>执行代码块') raise AttributeError('***着火啦,救火啊***') print('11111111') ####永远不会打印 print('0'*100) #------------------------------->会执行 #__exit__方法返回布尔值为true的值时,with代码块后面的代码会执行
class Open: def __init__(self,filepath,mode,encode='utf-8'): self.f=open(filepath,mode=mode,encoding=encode) self.filepath=filepath self.mode=mode self.encoding=encode def write(self,line): print('write') self.f.write(line) def __getattr__(self, item): return getattr(self.f,item) def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() return True with Open('a.txt','w') as f: #f=Open('a.txt','w') f.write('11\n') f.write('22\n') print(sssssssssssssss) #抛出异常,交给__exit__处理 f.write('33\n') # 这不执行 print('aaaaa')#执行
#被property装饰的属性会优先于对象的属性被使用,只有在属性sex定义property后才能定义sex.setter,sex.deleter class People: def __init__(self,name,SEX): self.name=name # self.__sex=SEX #这不调用@sex.setter def sex(self,value):方法 由于设置的是__sex 不是 sex,或者说__sex没有被@property装饰 self.sex=SEX #①由于sex被@property装饰,因此self.sex=SEX是去找@sex.setter def sex(self,value): 方法,而不是给对象赋值 @property def sex(self): return self.__sex #p1.__sex @sex.setter def sex(self,value): print('...') if not isinstance(value,str): raise TypeError('性别必须是字符串类型') self.__sex=value #② male给了value , self.__sex='male' @sex.deleter #del p1.sex的时候调用 def sex(self): del self.__sex #del p1.__sex p1=People('alex','male') #会调用 @sex.setter def sex(self,value): 方法是由于__init__中 self.sex=SEX 是给sex设置值了 p1.sex='female' #会调用@sex.setter def sex(self,value): 方法 del p1.sex print(p1.sex) #AttributeError: 'People' object has no attribute '_People__sex'
class Foo: def get_AAA(self): print('get的时候运行我啊') def set_AAA(self,value): print('set的时候运行我啊') def delete_AAA(self): print('delete的时候运行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA """ get的时候运行我啊 set的时候运行我啊 delete的时候运行我啊 """
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() print(obj.price) # 80.0 obj.price = 200 # 修改商品原价 print(obj.price) # 160.0 del obj.price # 删除商品原价
#实现类型检测功能 #第一关: class People: def __init__(self,name): self.name=name @property def name(self): return self.name p1=People('alex') #property自动实现了set和get方法属于数据描述符,比实例属性优先级高,因此你这写会触发property内置的set,抛出异常 #第二关:修订版 class People: def __init__(self,name): self.name=name #实例化就触发property @property def name(self): # return self.name #无限递归 print('get------>') return self.DouNiWan @name.setter def name(self,value): print('set------>') self.DouNiWan=value @name.deleter def name(self): print('delete------>') del self.DouNiWan p1=People('alex') #self.name实际是存放到self.DouNiWan里 print(p1.name) print(p1.name) print(p1.name) print(p1.__dict__) p1.name='egon' print(p1.__dict__) del p1.name print(p1.__dict__) #第三关:加上类型检查 class People: def __init__(self,name): self.name=name #实例化就触发property @property def name(self): # return self.name #无限递归 print('get------>') return self.DouNiWan @name.setter def name(self,value): print('set------>') if not isinstance(value,str): raise TypeError('必须是字符串类型') self.DouNiWan=value @name.deleter def name(self): print('delete------>') del self.DouNiWan p1=People('alex') #self.name实际是存放到self.DouNiWan里 p1.name=1
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
class MyType(type): def __call__(cls, *args, **kwargs): print(cls) obj = cls.__new__(cls, *args, **kwargs) print('在这里面..') print('==========================') obj.__init__(*args, **kwargs) return obj class Foo(metaclass=MyType): def __init__(self): self.name = 'alex' print('123') f = Foo() #调用 print(f.name) """ <class '__main__.Foo'> 在这里面.. ========================== 123 alex """
def test(x:int,y:int)->int: return x+y print(test.__annotations__) #{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
class Foo: def __get__(self, instance, owner): print('触发get') def __set__(self, instance, value): print('触发set') def __delete__(self, instance): print('触发delete') #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法 f1=Foo() f1.name='egon' f1.name del f1.name #疑问:什么时候,何地,会触发这三个方法的执行 #描述符分两种 #1:数据描述符:至少实现了__get__()和__set__() class Foo: def __set__(self, instance, value): print('set') def __get__(self, instance, owner): print('get') #2:非数据描述符:没有实现__set__() class Foo: def __get__(self, instance, owner): print('get')
#描述符Str class Str: def __get__(self, instance, owner): print('Str调用') def __set__(self, instance, value): print('Str设置...') def __delete__(self, instance): print('Str删除...') #描述符Int class Int: def __get__(self, instance, owner): print('Int调用') def __set__(self, instance, value): print('Int设置...') def __delete__(self, instance): print('Int删除...') class People: name=Str() age=Int() def __init__(self,name,age): #name被Str类代理,age被Int类代理, self.name=name self.age=age #何地?:定义成另一个类的类属性 #什么时候?:且看下列演示 p1=People('alex',18) #描述符Str的使用 p1.name p1.name='egon' del p1.name #描述符Int的使用 p1.age p1.age=18 del p1.age #咱们来瞅瞅到底发生了什么 print(p1.__dict__) print(People.__dict__) #补充 print(type(p1) == People) #type(obj)实际上是查看obj是由哪一个类实例化来的 print(type(p1).__dict__ == People.__dict__)
#描述符Str class Str: def __get__(self, instance, owner): print('Str调用') def __set__(self, instance, value): print('Str设置...') def __delete__(self, instance): print('Str删除...') class People: name=Str() def __init__(self,name,age): #name被Str类代理,age被Int类代理, self.name=name self.age=age p1=People('egon',18) #若是描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操做,于p1自己无关了,至关于覆盖了实例的属性 p1.name='egonnnnnn' p1.name print(p1.__dict__)#实例的属性字典中没有name,由于name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了 del p1.name
class Foo: def __set__(self, instance, value): print('set') def __get__(self, instance, owner): print('get') class Room: name=Foo() def __init__(self,name,width,length): self.name=name self.width=width self.length=length #name是一个数据描述符,由于name=Foo()而Foo实现了get和set方法,于是比实例属性有更高的优先级 #对实例的属性操做,触发的都是描述符的 r1=Room('厕所',1,1) r1.name r1.name='厨房' class Foo: def __get__(self, instance, owner): print('get') class Room: name=Foo() def __init__(self,name,width,length): self.name=name self.width=width self.length=length #name是一个非数据描述符,由于name=Foo()而Foo没有实现set方法,于是比实例属性有更低的优先级 #对实例的属性操做,触发的都是实例本身的 r1=Room('厕所',1,1) r1.name r1.name='厨房'
class Str: def __init__(self,name): self.name=name def __get__(self, instance, owner): print('get--->',instance,owner) return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Str('name') def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People('egon',18,3231.3) #调用 print(p1.__dict__) p1.name #赋值 print(p1.__dict__) p1.name='egonlin' print(p1.__dict__) #删除 print(p1.__dict__) del p1.name print(p1.__dict__)
class Str: def __init__(self,name): self.name=name def __get__(self, instance, owner): print('get--->',instance,owner) return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Str('name') def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary #疑问:若是我用类名去操做属性呢 People.name #报错,错误的根源在于类去操做属性时,会把None传给instance #修订__get__方法 class Str: def __init__(self,name): self.name=name def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Str('name') def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(People.name) #完美,解决
class Str: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) if not isinstance(value,self.expected_type): #若是不是指望的类型,则抛出异常 raise TypeError('Expected %s' %str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Str('name',str) #新增类型限制str def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People(123,18,3333.3)#传入的name因不是字符串类型而抛出异常
def decorate(cls): print('类的装饰器开始运行啦------>') return cls @decorate #无参:People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People('egon',18,3333.3)
def typeassert(**kwargs): def decorate(cls): print('类的装饰器开始运行啦------>',kwargs) return cls return decorate @typeassert(name=str,age=int,salary=float) #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People('egon',18,3333.3)
class ClassMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己, def feedback(): print('在这里能够加功能啊...') return self.func(owner) return feedback class People: name='linhaifeng' @ClassMethod # say_hi=ClassMethod(say_hi) def say_hi(cls): print('你好啊,帅哥 %s' %cls.name) People.say_hi() p1=People() p1.say_hi() #疑问,类方法若是有参数呢,好说,好说 class ClassMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己, def feedback(*args,**kwargs): print('在这里能够加功能啊...') return self.func(owner,*args,**kwargs) return feedback class People: name='linhaifeng' @ClassMethod # say_hi=ClassMethod(say_hi) def say_hi(cls,msg): print('你好啊,帅哥 %s %s' %(cls.name,msg)) People.say_hi('你是那偷心的贼') p1=People() p1.say_hi('你是那偷心的贼')
class StaticMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己, def feedback(*args,**kwargs): print('在这里能够加功能啊...') return self.func(*args,**kwargs) return feedback class People: @StaticMethod# say_hi=StaticMethod(say_hi) def say_hi(x,y,z): print('------>',x,y,z) People.say_hi(1,2,3) p1=People() p1.say_hi(4,5,6)
#type元类,是全部类的类,利用type模拟class关键字的建立类的过程 class Bar2: x=1 def run(self): print('%s is runing' %self.name) print(Bar2.__bases__) print(Bar2.__dict__) #用type模拟Bar2 def run(self): print('%s is runing' %self.name) class_name='Bar' bases=(object,) class_dic={ 'x':1, 'run':run } Bar=type(class_name,bases,class_dic) print(Bar) #<class '__main__.Bar'> print(type(Bar)) #<class 'type'> print(Bar.__bases__) print(Bar.__dict__) #就是新建了一个空类 class Spam2: pass print(Spam2) print(Spam2.__bases__) print(Spam2.__dict__) #用type模拟Spam2 Spam=type('Spam',(),{}) print(Spam) print(Spam.__bases__) print(Spam.__dict__)
class Poo(metaclass=type): #就是执行了 type('Poo',(object,),{'x':1,'run':...}) x=1 def run(self): print('running') #__init__ class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #这的self就是Foo类 for key in class_dic: if not callable(class_dic[key]):continue if not class_dic[key].__doc__: raise TypeError('你没写注释,赶忙去写') # type.__init__(self,class_name,class_bases,class_dic) class Foo(metaclass=Mymeta): #就是执行了 Foo=Mymeta('Foo',(object,),{'x':1,'run':...}) x=1 def run(self): 'run function' print('running') #__call__ class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): pass def __call__(self, *args, **kwargs):# print(self) 这的self就是Foo类 obj=self.__new__(self) #建一个空对象 self.__init__(obj,*args,**kwargs) #注意参数obj obj.name='tom' return obj #把对象返回 class Foo(metaclass=Mymeta): x=1 def __init__(self,name): self.name=name #obj.name='tom' def run(self): print('running') f=Foo('tom') print(f) print(f.name)
""" exec:3个参数 参数 1:包含一系列python代码的字符串 参数 2:全局做用域(字典形式),若是不指定,默认为globals() 参数 3:局部做用域(字典形式),若是不指定,默认为locals() 能够把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中 """ g={ 'x':1, 'y':2 } l={} exec(''' global x,z x=100 z=200 m=300 ''',g,l) print(g) #{'x': 100, 'y': 2,'z':200,......} print(l) #{'m': 300}
class Foo: def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) obj=Foo() #一、要想让obj这个对象变成一个可调用的对象,须要在该对象的类中定义一个方法__call__方法,该方法会在调用对象时自动触发 #二、调用obj的返回值就是__call__方法的返回值 res=obj(1,2,3,x=1,y=2) """ <__main__.Foo object at 0x0000000000B0BEB8> (1, 2, 3) {'x': 1, 'y': 2} """
class OldboyTeacher(object): school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) t1=OldboyTeacher('egon',18) print(type(t1)) #查看对象t1的类是<class '__main__.OldboyTeacher'> print(type(OldboyTeacher)) # 结果为<class 'type'>,证实是调用了type这个元类而产生的OldboyTeacher,即默认的元类为type """ 一: python中一切皆为对象。 全部的对象都是实例化或者说调用类而获得的(调用类的过程称为类的实例化),好比对象t1是调用类OldboyTeacher获得的 元类-->实例化-->类OldboyTeacher-->实例化-->对象t1 二: class关键字建立类的流程分析: 用class关键字定义的类自己也是一个对象,负责产生该对象的类称之为元类(元类能够简称为类的类),内置的元类为type class关键字在帮咱们建立类时,必然帮咱们调用了元类OldboyTeacher=type(...),那调用type时传入的参数是什么呢? 必然是类的关键组成部分,一个类有三大组成部分,分别是 一、类名class_name='OldboyTeacher' 二、基类们class_bases=(object,) 三、类的名称空间class_dic,类的名称空间是执行类体代码而获得的 调用type时会依次传入以上三个参数 综上,class关键字帮咱们建立一个类应该细分为如下四个过程: 一、拿到类名:class_name='OldboyTeacher' 二、拿到类的基类们:class_bases=(object,) 三、执行类体代码,拿到类的名称空间:class_dic={...} 四、调用元类获得类:OldboyTeacher=type(class_name,class_bases,class_dic) 三: 自定义元类控制类OldboyTeacher的建立: 一个类没有声明本身的元类,默认他的元类就是type,除了使用内置元类type, 咱们也能够经过继承type来自定义元类,而后使用metaclass关键字参数为一个类指定元类 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 pass class OldboyTeacher(object,metaclass=Mymeta): # OldboyTeacher=Mymeta('OldboyTeacher',(object),{...}) school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) """ 四: 自定义元类能够控制类的产生过程,类的产生过程其实就是元类的调用过程, 即OldboyTeacher=Mymeta('OldboyTeacher',(object),{...}), 调用Mymeta会先产生一个空对象OldoyTeacher, 而后连同调用Mymeta括号内的参数一同传给Mymeta下的__init__方法,完成初始化,因而咱们能够 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 def __init__(self,class_name,class_bases,class_dic): # print(self) #<class '__main__.OldboyTeacher'> # print(class_bases) #(<class 'object'>,) # print(class_dic) #{'__module__': '__main__', '__qualname__': 'OldboyTeacher', 'school': 'oldboy', '__init__': <function OldboyTeacher.__init__ at 0x102b95ae8>, 'say': <function OldboyTeacher.say at 0x10621c6a8>} super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 重用父类的功能 if class_name.islower(): raise TypeError('类名%s请修改成驼峰体' %class_name) if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) == 0: raise TypeError('类中必须有文档注释,而且文档注释不能为空') class OldboyTeacher(object,metaclass=Mymeta): # OldboyTeacher=Mymeta('OldboyTeacher',(object),{...}) """ 类OldboyTeacher的文档注释 """ school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) """ 五: 自定义元类控制类OldboyTeacher的调用: 储备知识:__call__ 调用一个对象,就是触发对象所在类中的__call__方法的执行,若是把OldboyTeacher也当作一个对象, 那么在OldboyTeacher这个对象的类中也必然存在一个__call__方法 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 def __call__(self, *args, **kwargs): print(self) #<class '__main__.OldboyTeacher'> print(args) #('egon', 18) print(kwargs) #{} return 123 class OldboyTeacher(object,metaclass=Mymeta): school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) # 调用OldboyTeacher就是在调用OldboyTeacher类中的__call__方法 # 而后将OldboyTeacher传给self,溢出的位置参数传给*,溢出的关键字参数传给** # 调用OldboyTeacher的返回值就是调用__call__的返回值 t1=OldboyTeacher('egon',18) print(t1) #123 """ 六: 默认地,调用t1=OldboyTeacher('egon',18)会作三件事 一、产生一个空对象obj 二、调用__init__方法初始化对象obj 三、返回初始化好的obj 对应着,OldboyTeacher类中的__call__方法也应该作这三件事 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'> #一、调用__new__产生一个空对象obj obj=self.__new__(self) # 此处的self是类OldoyTeacher,必须传参,表明建立一个OldboyTeacher的对象obj #二、调用__init__初始化空对象obj self.__init__(obj,*args,**kwargs) #三、返回初始化好的对象obj return obj class OldboyTeacher(object,metaclass=Mymeta): school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) t1=OldboyTeacher('egon',18) print(t1.__dict__) #{'name': 'egon', 'age': 18} """ 七: 上例的__call__至关于一个模板,咱们能够在该基础上改写__call__的逻辑从而控制调用OldboyTeacher的过程, 好比将OldboyTeacher的对象的全部属性都变成私有的 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'> #一、调用__new__产生一个空对象obj obj=self.__new__(self) # 此处的self是类OldoyTeacher,必须传参,表明建立一个OldboyTeacher的对象obj #二、调用__init__初始化空对象obj self.__init__(obj,*args,**kwargs) # 在初始化以后,obj.__dict__里就有值了 obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()} #三、返回初始化好的对象obj return obj class OldboyTeacher(object,metaclass=Mymeta): school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) t1=OldboyTeacher('egon',18) print(t1.__dict__) #{'_OldboyTeacher__name': 'egon', '_OldboyTeacher__age': 18} """ 八: 再看属性查找: 上例中涉及到查找属性的问题,好比self.__new__ 结合python继承的实现原理+元类从新看属性的查找应该是什么样子呢??? 在学习完元类后,其实咱们用class自定义的类也全都是对象(包括object类自己也是元类type的 一个实例,能够用type(object)查看), 咱们学习过继承的实现原理,若是把类当成对象去看,将下述继承应该说成是:对象OldboyTeacher继承对象Foo,对象Foo继承对象Bar,对象Bar继承对象object """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 n=444 def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'> obj=self.__new__(self) self.__init__(obj,*args,**kwargs) return obj class Bar(object): n=333 class Foo(Bar): n=222 class OldboyTeacher(Foo,metaclass=Mymeta): n=111 school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) print(OldboyTeacher.n) #自下而上依次注释各个类中的n=xxx,而后从新运行程序,发现n的查找顺序为OldboyTeacher->Foo->Bar->object->Mymeta->type """ 九: 因而属性查找应该分红两层,一层是对象层(基于c3算法的MRO)的查找,另一个层则是类层(即元类层)的查找 #查找顺序: #一、先对象层:OldoyTeacher->Foo->Bar->object #二、而后元类层:Mymeta->type 分析下元类Mymeta中__call__里的self.__new__的查找 """ class Mymeta(type): n=444 def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'> obj=self.__new__(self) print(self.__new__ is object.__new__) #True class Bar(object): n=333 # def __new__(cls, *args, **kwargs): # print('Bar.__new__') class Foo(Bar): n=222 # def __new__(cls, *args, **kwargs): # print('Foo.__new__') class OldboyTeacher(Foo,metaclass=Mymeta): n=111 school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) # def __new__(cls, *args, **kwargs): # print('OldboyTeacher.__new__') OldboyTeacher('egon',18) #触发OldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找 """ 十: 总结,Mymeta下的__call__里的self.__new__在OldboyTeacher、Foo、Bar里都没有找到__new__的状况下, 会去找object里的__new__,而object下默认就有一个__new__,因此即使是以前的类均未实现__new__, 也必定会在object中找到一个,根本不会、也根本不必再去找元类Mymeta->type中查找__new__ 咱们在元类的__call__中也能够用object.__new__(self)去造对象 但咱们仍是推荐在__call__中使用self.__new__(self)去创造空对象, 由于这种方式会检索三个类OldboyTeacher->Foo->Bar,而object.__new__则是直接跨过了他们三个 """ class Mymeta(type): #只有继承了type类才能称之为一个元类,不然就是一个普通的自定义类 n=444 def __new__(cls, *args, **kwargs): obj=type.__new__(cls,*args,**kwargs) # 必须按照这种传值方式 print(obj.__dict__) # return obj # 只有在返回值是type的对象时,才会触发下面的__init__ return 123 def __init__(self,class_name,class_bases,class_dic): print('run。。。') class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object),{...}) n=111 school='oldboy' def __init__(self,name,age): self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) print(type(Mymeta)) #<class 'type'> """ 产生类OldboyTeacher的过程就是在调用Mymeta,而Mymeta也是type类的一个对象,那么Mymeta之因此能够调用,必定是在元类type中有一个__call__方法 该方法中一样须要作至少三件事: class type: def __call__(self, *args, **kwargs): #self=<class '__main__.Mymeta'> obj=self.__new__(self,*args,**kwargs) # 产生Mymeta的一个对象 self.__init__(obj,*args,**kwargs) return obj """
""" 练习二:在元类中控制自定义的类无需__init__方法 1.元类帮其完成建立对象,以及初始化操做; 2.要求实例化时传参必须为关键字形式,不然抛出异常TypeError: must use keyword argument 3.key做为用户自定义类产生对象的属性,且全部属性变成大写 """ class Mymetaclass(type): # def __new__(cls,name,bases,attrs): # update_attrs={} # for k,v in attrs.items(): # if not callable(v) and not k.startswith('__'): # update_attrs[k.upper()]=v # else: # update_attrs[k]=v # return type.__new__(cls,name,bases,update_attrs) def __call__(self, *args, **kwargs): if args: raise TypeError('must use keyword argument for key function') obj = object.__new__(self) #建立对象,self为类Foo for k,v in kwargs.items(): obj.__dict__[k.upper()]=v return obj class Chinese(metaclass=Mymetaclass): country='China' tag='Legend of the Dragon' #龙的传人 def walk(self): print('%s is walking' %self.name) p=Chinese(name='egon',age=18,sex='male') print(p.__dict__)
class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #控制类Foo的建立 super(Mymeta,self).__init__(class_name,class_bases,class_dic) def __call__(self, *args, **kwargs): #控制Foo的调用过程,即Foo对象的产生过程 obj = self.__new__(self) self.__init__(obj, *args, **kwargs) obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()} return obj class Foo(object,metaclass=Mymeta): # Foo=Mymeta(...) def __init__(self, name, age,sex): self.name=name self.age=age self.sex=sex obj=Foo('egon',18,'male') print(obj.__dict__)
#步骤五:基于元类实现单例模式 # 单例:即单个实例,指的是同一个类实例化屡次的结果指向同一个对象,用于节省内存空间 # 若是咱们从配置文件中读取配置来进行实例化,在配置相同的状况下,就不必重复产生对象浪费内存了 #settings.py文件内容以下 HOST='1.1.1.1' PORT=3306 #方式一:定义一个类方法实现单例模式 import settings class Mysql: __instance=None def __init__(self,host,port): self.host=host self.port=port @classmethod def singleton(cls): if not cls.__instance: cls.__instance=cls(settings.HOST,settings.PORT) return cls.__instance obj1=Mysql('1.1.1.2',3306) obj2=Mysql('1.1.1.3',3307) print(obj1 is obj2) #False obj3=Mysql.singleton() obj4=Mysql.singleton() print(obj3 is obj4) #True #方式二:定制元类实现单例模式 import settings class Mymeta(type): def __init__(self,name,bases,dic): #定义类Mysql时就触发 # 事先先从配置文件中取配置来造一个Mysql的实例出来 self.__instance = object.__new__(self) # 产生对象 self.__init__(self.__instance, settings.HOST, settings.PORT) # 初始化对象 # 上述两步能够合成下面一步 # self.__instance=super().__call__(*args,**kwargs) super().__init__(name,bases,dic) def __call__(self, *args, **kwargs): #Mysql(...)时触发 if args or kwargs: # args或kwargs内有值 obj=object.__new__(self) self.__init__(obj,*args,**kwargs) return obj return self.__instance class Mysql(metaclass=Mymeta): def __init__(self,host,port): self.host=host self.port=port obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,全部的实例应该指向一个内存地址 obj2=Mysql() obj3=Mysql() print(obj1 is obj2 is obj3) obj4=Mysql('1.1.1.4',3307) #方式三:定义一个装饰器实现单例模式 import settings def singleton(cls): #cls=Mysql _instance=cls(settings.HOST,settings.PORT) def wrapper(*args,**kwargs): if args or kwargs: obj=cls(*args,**kwargs) return obj return _instance return wrapper @singleton # Mysql=singleton(Mysql) class Mysql: def __init__(self,host,port): self.host=host self.port=port obj1=Mysql() obj2=Mysql() obj3=Mysql() print(obj1 is obj2 is obj3) #True obj4=Mysql('1.1.1.3',3307) obj5=Mysql('1.1.1.4',3308) print(obj3 is obj4) #False