python类高级话题
1、变量名压缩 class 语句内开头 有两个下划线,但结尾没有两个下划线的变量名会自动扩张,从而包含所在类的名称。例如:象spam类内__x这样的变量名会自动变成 _spam__x.原始的变量名会在开头家一个下划线,然后是再加上所在类的类名。这一规则适用了每个开头有两个下划线 的变量名,包括方法名称和实例属性名称。(例如:在spam类内,self.__x实例属性会变成self._spam__x) 2、方法是对象:绑定或无绑定 无绑定类方法对象: 无self 通过对类进行点号运算从而获取函数的属性,会传回无绑定方法对象,调用该方法时,必须提供实例对象作为第一个参数,在python3.0中,一个无绑定方法和一个简单函数相同。可以通过类名来调用,在python2.6中,他是一个特殊的类型,并且不提供一个实例就无法调用 绑定实例方法对象: self+函数对 通过对实例进行全运算,从而获取类的汗水属性,会传回绑定方法对象。python在绑定方法对象中自动实现实例和函数的打包,所以不用传递实例去调用该方法。 例如: class Spam: def doit(self,message): print(message) 在下面代码中,会传回绑定方法对象,把实例(object1)和方法函数(spam.doit)打包起来。我们可以把这个绑定方法赋值给另外一个变量。然后像函数那样进行调用。 object1 = spam() x = object1.doit x('hello world') 另一方面,如果对类进行点号运算来获得doit就会获得无绑定方法对象。也就是函数对象的引用值。要调用这个类方法时,必须传入实例作为最左侧参数 例如: object2 = Spam() t = Spam.doit t(object2,'howdy') 扩展一下:如果我们引用的self属性是引用类中的函数,那么相同的规则也适用于类的方法。self.method表达式是邦定方法,因为self是实例对象。 例如: class C: def m1(self,n): print('m1=',n) def m2(self,t): x = self.m1 #这里是通过实例和方法打包,是绑定方法。 x(t)#在这里调用绑定方法不需要传入实例 print('m2=',t) c = C() c.m2(88) print('#'*8) C.m2(c,77) print('-'*8) class B: def m1(self,n): print('m1=',n) def m2(self,t): x = B.m1 #这里通过类来获取类中的函数,是无绑定方法对象 x(self,t)#这里使用时需要传入一个类对象。 print('m2=',t) b = B() B.m2(b,99) print('@'*8) b.m2(66) #输出结果: m1= 88 m2= 88 ######## m1= 77 m2= 77 -------- m1= 99 m2= 99 @@@@@@@@ m1= 66 m2= 66 3、在python3.0中无绑定方法是函数 在python3.0中已经删除"无绑定方法"的概念,但是还是可以使用。在上面介绍的绑定方法,在python3.0中只当作一个简单函数来使用。简单函数不期待传递给他一个实例,非简单函数期待传递一个实例。 此外:在python3.0中不使用一个实例而调用一个方法没有问题,只要这个方法不期待一个实例,并且你通过类调用它而不是通过一个实例调用它。也就是说,只有对通过实例调用,python3.0才会向方法传递一个实例。当通过一个类调用的时候,只有在方法期待一个实例的时候,才必须手动传递一个实例。 class Selfless: def __init__(self,data): self.data = data def selfless(arg1,arg2): return arg1+arg2 def normal(self,arg1,arg2): return self.data+arg1+arg2 x = Selfless(2) print(x.normal(3,4)) print('-'*8) print(Selfless.normal(x,3,4)) print('-'*8) print(Selfless.selfless(3,4)) #在python3.0中可以通过一个类去调用这个类的普通方法,但是在python2.6中不行,会抱错。 print('-'*8) #print(x.selfess(3,4)) 不能通过实例去调用一个类的普通方法 4、多重集成 在传统类中(默认的类,直到python3.0),属性搜索处理对所有路径深度优先 ,直到继承树的顶端,然后从左到右 在新式类(以及python.30的所有类中)属性搜索处理沿着树层级,以及更宽广优先的方式。 例如:使用__dict__列出实例属性 class Listinstance: ''' Mix-in class that provides a formatted print() or str() of instance of via inheritance of __str__, coded here:displays instance attrs only;self is the instance of lowest class; uses __x names to avoid clashing with client's attrs ''' def __str__(self): return '<Instance of %s, adderss %s:\n%s>'%( self.__class__.__name__,#每个实例都有一个内置的__class__属性,它引用创建 自己的类,并且每一个类都有一个__name__属性。他引用头部的名称。 id(self), #返回该对象的内存地址 self.__attrnames() ) def __attrnames(self): result = '' for attr in sorted(self.__dict__): result+='\tname %s=%s\n'%(attr,self.__dict__[attr]) return result s = spam(12) print(s) #输出: <Instance of spam, adderss 3073187084: name data=12 > 例如:使用dir列出继承的所有属性 class ListInherited: ''' Use dir() to collect both instance attrs and names inherited from its classes; python3.0 shows more names than 2.6 because of the implied object supperclass in the new-style class model; getattr() fetches inherited names not in self.__dict__;use __str__,not __repr__ or else this loops when printing bound methods ''' def __str__(self): return '<Instance of %s, address %s:\n%s>'(self.__class_.__name, id(self), self.__attrnames()) def __attrnames(self): result = '' for attr in dir(self): if attr[:2] == '__' and attr[-2:] == '__': result+='\tname %s = <>'%attr else: result += '\tname %s=%s\n'%(attr,getattr(self,attr)) return result 例如:列出类树中的每个对象的属性 class ListTree: ''' Mix-in that returns an __str__ trace of the entire class tree and all its objects'attrs at and above self; run by print(),str() returns constructed string; uses __x attr names to void impacting clients; uses generator expr to recurse to superclasses; uses str.format() to make substituion clear ''' def __str__(self): self.__visited = {} return '<Instance of {0}, address {1}:\n{2}{3}'.format( self.__class__.__name__, id(self), self.__attrnames(self,0), self.__listclass(self.__class_,4) ) def __listclass(self,aClass,indent): dots = '.'*indent if aClass in self.__visited: return '\n{0}<Class {1}:,address {2}:(see above)>\n'.format( dots, aClass.__name, id(aClass) ) else: self.__visited[aClass]=True genabove = (self.__listclass(c,indent+4) for c in aClass.__base__) return '\n{0}<Class {1} , address {2}:\n{3}{4}{5}>\n'.format( dots, aClass.__name__, id(aClass), self.__attrnames(aClass,indent), ''.join(genabove), dots ) def __attrnames(self,obj,indent): spaces = ' ' * (indent+4) result = '' for attr in sorted(obj.__dict__): if attr.startwith('__') and attr.endwith('__'): resutl +=spaces +'{0}=<>\n'.format(attr) else: result ++space+'{0}={1}\n'.format(attr,getattr(obj,attr)) return result 4、新式类 对于python3.0来说,所有类都是我们所谓的”新式类“,不管他们是否显示继承object.所有类都继承自object.不管显式还是隐式,所有对象都是object的实例 在python2.6及其以前版本,类必须继承自类看作是新式”object,并且获得新式类的特性。 5、新式类的变化 1)类和类型合并 类现在就是类型,并且类型现在就是类,实际上,这二者基本上是同义词。type(I)内置函数返回一个创建这个实例I的类。而不是一个通用实例类型,并且,通常是和I.__class__相同。此外,雷氏type类的实例,type可能子类化 6、__slots__ 如果一个字类继承一个没有__slots__的超类,那么超类的__dict__属性总是可以访问的,使得字类的__slots__没有意义 如果一个超类定义了一个与超类相同的slots名称,超类slots定义的名称只有通过从直接超类获取其描述符才能访问 由于一个超类__slots__声明的含义受到它出现其中类的限制,所以一个字类将有一个__dict__除非他也声明了一个__slots__ 通常从列出实例属性这方面来看,多数类的slots可能需要手动类树爬升、dir用法或者把slot名称当作不同的名称领域的政策 7、特性 适用条件是这个类必须继承object class classic: def getx(self) return self.__x def setx(self,data): self.__x =data def delx(self) self.__x = None x = property(getx,setx,delx,None) 8、__getattribute__方法只适用于新式类,可以让类拦截所有属性的引用,而不是局限于未定义的引用 9、静态方法和类方法 不用一个实例就可以调用 :静态方法 传递一个类而不是一个实例:类方法 10、静态方法和类方法使用实例 静态方法: class Spam: numInstances = 0 def __init__(self): Spam.numInstances +=1 def printNumInstance(): print("Number of instance:",Spam.numInstances) printNumInstance = staticmethod(printNumInstance) a = Spam() b = Spam() c = Spam() Spam.printNumInstance() a.printNumInstance() 继承: class Sub(Spam): def printNumInstance(): print('extra stauff...') Spam.printNumInstance() printNumInstance = staticmethod(printNumInstance) a = Sub() b = Sub() a.printNumInstance() Sub.printNumInstance() Spam.printNumInstance() 类方法 class Spam: numInstances = 0 def __init__(self): Spam.numInstances +=1 def printNumInstance(cls): print("Num of instnace:", cls.numInstances) printNumInstance = classmethod(printNumInstance) a,b = Spam(),Spam() a.printNumInstance() Spam.printNumInstance() 继承方法同静态方法相同 11、装饰器和元类 例如: class Spam: numInstances = 0 def __init__(self): Spam.numInstances +=1 @staticmethod def printNumInstance(): print("Number of instance:",Spam.numInstances) a = Spam() b = Spam() c = Spam() Spam.printNumInstance() a.printNumInstance()