重写__init__不会自动调用基类的__init__,当从一个带构造器__init()__的类派生,如果你不去覆盖__init__(),它将会被继承并自动调用。但如果你在子类中覆盖了__init__(),子类被实例化时,基类的__init__()就不会被自动调用。
classP(object):
def__init__(self):
print("callingPsconstructor")
classC(P):
def__init__(self):
print("callingCsconstructor")
c=C()#callingCsconstructor
classC(P):
def__init__(self):
P.__init__(self)
print("callingCsconstructor")
c=C()
callingPsconstructor
callingCsconstructor
#子类的__init__()方法首先调用了基类的的__init__()方法。这是相当普遍(不是强制)的做法,用来设置初始化基类,然后可以执行子类内部的设置。
#这个规则之所以有意义的原因是,你希望被继承的类的对象在子类构造器运行前能够很好地被初始化或作好准备工作,因为它(子类)可能需要或设置继承属性。
#Python使用基类名来调用类方法,super()内建函数引入到Python:
classC(P):
def__init__(self):
super(C,self).__init__()
print("callingCsconstructor")
#使用super()的漂亮之处在于,你不需要明确给出任何基类名字!使用super()的重点,是你不需要明确提供父类。
#这意味着如果你改变了类继承关系,你只需要改一行代码(class语句本身)而不必在大量代码中去查找所有被修改的那个类的名字。
从标准类型派生,不可变类型的例子
classRoundFloat(float):
def__new__(cls,val):
returnfloat.__new__(cls,round(val,2))
print(RoundFloat(1.))#1.6
print(RoundFloat(1.))#1.59
print(RoundFloat(-1.))#-2.0
#改进
classRoundFloat(float):
def__new__(cls,val):
returnsuper(RoundFloat,cls).__new__(cls,round(val,2))
print(RoundFloat(1.))#1.6
print(RoundFloat(1.))#1.59
print(RoundFloat(-1.))#-2.0
可变类型的例子,子类化一个可变类型与此类似,你可能不需要使用__new__()(或甚至__init__()),因为通常设置不多。一般情况下,你所继承到的类型的默认行为就是你想要的。
classSortedKeyDict(dict):
defkeys(self):
returnsorted(super(SortedKeyDict,self).keys())
#字典(dictionary)可以由dict(),dict(mapping),dict(sequence_of_2_tuples),或者dict(**kwargs)来创建。
d=SortedKeyDict(((zheng-cai,67),(hui-jun,68),(xin-yi,2)))
print(Byiterator:.ljust(12),[keyforkeyind])#Byiterator:[zheng-cai,hui-jun,xin-yi]
print(Bykeys():.ljust(12),d.keys())#Bykeys():[hui-jun,xin-yi,zheng-cai]
当使用多重继承时,有两个不同的方面要记住。首先,还是要找到合适的属性。另一个就是当你重写方法时,如何调用对应父类方法以“发挥他们的作用”,同时,在子类中处理好自己的义务。
方法解释顺序MRO的版本,它必须取代经典类中的算法。算法基本思想是根据每个祖先类的继承结构,编译出一张列表,包括搜索到的类,按策略删除重复的。然而,在Python核心开发人员邮件列表中,有人指出,在维护单调性方面失败过(顺序保存)。
classP1:#(object):#parentclass1父类1
deffoo(self):
print(calledP1-foo())
classP2:#(object):#parentclass2父类2
deffoo(self):
print(calledP2-foo())
defbar(self):
print(calledP2-bar())
classC1(P1,P2):#child1der.fromP1,P2#子类1,从P1,P2派生
pass
classC2(P1,P2):#child2der.fromP1,P2#子类2,从P1,P2派生
defbar(self):
print(calledC2-bar())
classGC(C1,C2):#definegrandchildclass#定义子孙类
pass#derivedfromC1andC2#从C1,C2派生
gc=GC()
gc.foo()#GC==C1==C2==P1calledP1-foo()
gc.bar()#GC==C1==C2calledC2-bar()
P2.bar(gc)#calledP2-bar()
print(GC.__mro__)#(class__main__.GC,class__main__.C1,class__main__.C2,class__main__.P1,class__main__.P2,classobject)
大部分类都是单继承的,多重继
承只限用在对两个完全不相关的类进行联合。这就是术语mixin类(或者“mix-ins”)的由来。继承的问题是由于在新式类中,需要出现基类,这样就在继承结构中,形成了一个菱形。D的实例上溯时,不应当错过C,但不能两次上溯到A(因为B和C都从A派生)。代码中仅仅是在两个类声明中加入了(object),对吗?没错,但从图中,你可以看出,继承结构已变成了一个菱形;真正的问题就存在于MRO了。
issubclass()布尔函数判断一个类是另一个类的子类或子孙类。它有如下语法:issubclass(sub,sup)
issubclass()返回True的情况:给出的子类sub确实是父类sup的一个子类(反之,则为False)。一个类可视为其自身的子类,所以,这个函数如果当
sub就是sup,或者从sup派生而来,则返回True。issubclass()的第二个参数可以是可能的父类组成的tuple(元组),这时,只要第一个参数是给定元组中任何一个候选类的子类时,就会返回True。
isinstance()布尔函数在判定一个对象是否是另一个给定类的实例时,非常有用。它有如下语法:isinstance(obj1,obj2)
isinstance()在obj1是类obj2的一个实例,或者是obj2的子类的一个实例时,返回True(反之,则为False)。isinstance()也可以使用一个元组(tuple)作为第二个参数。如果第一个参数是第二个参数中给定元组的任何一个候选类型或类的实例时,就会返回True。
*attr()系列函数可以在各种对象下工作,不限于类(class)和实例(instances)。当使用这些函数时,你传入你正在处理的对象作为第一个参数,但属性名,也就是这些函数的第二个参数,是这些属性的字符串名字。换句话说,在操作obj.attr时,就相当于调用*attr(obj,attr....)系列函数。hasattr()函数是Boolean型的,它的目的就是为了决定一个对象是否有一个特定的属性,一般用于访问某属性前先作一下检查。getattr()和setattr()函数相应地取得和赋值给对象的属性,getattr()会在你试图读取一个不存在的属性时,引发AttributeError异常,除非给出那个可选的默认参数。setattr()将要么加入一个新的属性,要么取代一个已存在的属性。而delattr()函数会从一个对象中删除属性。
classmyClass(object):
def__init__(self):
self.foo=
myInst=myClass()
print(hasattr(myInst,foo))#True
print(getattr(myInst,foo))#
print(hasattr(myInst,bar))#False
#getattr(myInst,bar)
print(getattr(myInst,bar,oops!))#oops!
setattr(myInst,bar,myattr)
print(dir(myInst))#[__doc__,__module__,bar,foo]
print(getattr(myInst,bar))#sameasmyInst.bar#等同于myInst.barmyattr
delattr(myInst,foo)
print(dir(myInst))#[__doc__,__module__,bar]
print(hasattr(myInst,foo))#False
??dir()作用在实例上(经典类或新式类)时,显示实例变量,还有在实例所在的类及所有它的基类中定义的方法和类属性。
??dir()作用在类上(经典类或新式类)时,则显示类以及它的所有基类的__dict__中的内容。但它不会显示定义在元类(metaclass)中的类属性。
??dir()作用在模块上时,则显示模块的__dict__的内容。(这没改动)。
??dir()不带参数时,则显示调用者的局部变量。(也没改动)。
??关于更多细节:对于那些覆盖了__dict__或__class__属性的对象,就使用它们;出于向后兼容的考虑,如果已定义了__members__和__methods__,则使用它们。
super()是一个工厂函数,它创造了一个superobject,为一个给定的类使用__mro__去查找相应的父类。很明显,它从当前所找到的类开始搜索MRO。super()的主要用途,是来查找父类的属性,比如,super(MyClass,self).__init__()。如果你没有执行这样的查找,你可能不需要使用super()。
vars()内建函数与dir()相似,只是给定的对象参数都必须有一个__dict__属性。vars()返回一个字典,它包含了对象存储于其__dict__中的属性(键)及值。如果提供的对象没有这样一个属性,则会引发一个TypeError异常。如果没有提供对象作为vars()的一个参数,它将显示一个包含本地名字空间的属性(键)及其值的字典,也就是,locals()。
classC(object):
pass
c=C()
c.foo=
c.bar=Python
print(c.__dict__)#{foo:,bar:Python}
print(vars(c))#{foo:,bar:Python}
print(vars())#{__name__:__main__,__doc__:None,__package__:None,__loader__:_frozen_importlib_external.SourceFileLoaderobjectat0xEF9FB0,__spec__:None,__annotations__:{},__builtins__:modulebuiltins(built-in),__file__:d:\\python\\aa.py,__cached__:None,C:class__main__.C,c:__main__.Cobjectat0xEFADF0}
print(locals())#{__name__:__main__,__doc__:None,__package__:None,__loader__:_frozen_importlib_external.SourceFileLoaderobjectat0xFEB0,__spec__:None,__annotations__:{},__builtins__:modulebuiltins(built-in),__file__:d:\\python\\aa.py,__cached__:None,C:class__main__.C,c:__main__.Cobjectat0xFE1B6DF0}
预览时标签不可点收录于话题#个上一篇下一篇