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()