方法 | 调用时间 | 功能 |
---|---|---|
init | 当实例对象创建之后被调用 | 用于设置对象属性的一些初始值 |
new | 当实例对象创建之前被调用 | 用于创建实例然后返回该实例,是个静态方法 |
总结:
#定义父类A
class A(object): #
def __new__(cls,x): #至少要有一个参数cls,代表要实例化的类
print('this is in A.__new__,and x is ',x) # 描述性语句
return super(A,cls).__new__(cls)
#定义子类B
class B(A):
def __new__(cls,z): #至少要有一个参数cls,代表要实例化的类
print('this is in B.__new__,and z is ',z) # 描述性语句
return object.__new__(cls) #返回object的__new__出来的实例
# 或者
return A.__new__(cls,z) #返回父类A的__new__出来的实例
1、__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供;
2、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例。
__init__方法的注意事项:
__init__有一个参数self,就是__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。
我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节。
self和super的区别:
1、self是首先调用自身的方法如果自身没有再去父类中找;super是直接从父类中找方法;
2、self是类,super是预编译指令;
3、self class 和super calss的输出是一样的;
4、super() 在类的继承里,实现父类多次被子类调用时只执行一次, 优化了执行逻辑;
定义类的基本范例:
class Foo: #定义一个类
def bar(self,message): #定义类中的方法bar
print(message)
a=Foo() #定义变量a指向类Foo的实例化对象Foo()
a.bar("Hello") #变量a调用类Foo的方法bar(),"hello"为传递给形参“message”的实参
或者
Foo().bar("Hello,Python.") #避免定义变量a,直接对实例化对象调用类方法bar()
super在继承中的调用:
当存在继承关系时,若需要在子类中调用父类的方法,此时最简单的方法是:把对象调用转换成类调用,需要注意此时self参数需要显式传递。
典例如下——基础class继承的定义:
class FooParent: #定义父类FooParent
def bar(self,message): #定义父类的方法bar
print(message)
class FooChild(FooParent): #定义子类FooChild
def bar(self,message): #定义子类的方法bar
FooParent.bar(self,message) #方法一:在子类中直接调用父类的方法,此时需将“对象调用”转换为“类调用”
#或者
super(FooChild,self).bar(message) #方法二:直接调用super()机制
#此时self参数需要显式传递
FooChild().bar("Hello,Python.")
>>>
Hello,Python.
上述实例的缺点如下:
(1)如果修改了父类名称,那么在子类中会涉及多处修改
(2)Python是允许多继承的语言,如上所示的方法在多继承时就需要重复写多次,显得累赘。
为了解决这些问题,Python引入了super()机制:
#子类直接显示调用父类的方法
class A: #定义父类A
def __init__(self): #定义父类A的初始化方法
print("Enter A")
print("Leave A")
class B(A): #定义继承子类B
def __init__(self):
print("Enter B")
A.__init__(self)
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
A.__init__(self)
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
A.__init__(self)
print("Leave D")
class E(B,C,D):
def __init__(self):
print("Enter E")
B.__init__(self)
C.__init__(self)
D.__init__(self)
print("Leave E")
E() # 实例化对象
#该方法的执行顺序很好理解,唯一需要注意的是公共父类A被执行了多次。
>>>
Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E
#子类使用super机制调用父类的方法
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self):
print("Enter B")
super(B,self).__init__()
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
super(C,self).__init__()
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
super(D,self).__init__()
print("Leave D")
class E(B,C,D):
def __init__(self):
print("Enter E")
super(E,self).__init__()
print("Leave E")
E() #实例化对象
#super机制可保证公共父类仅被执行一次,执行的顺序是按照MRO(Method Resolution Order)方法解析顺序进行的.
>>>
Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E
这种形式在__init__方法中,只有一个self,指的是实例本身,包含两个属性,name, score。它允许定义一个空的结构,当新数据来时,可以直接添加。实例化时,需要实例化之后,再进行赋值。
class Game:# 定义Game类
def __init__(self): #创建类中的函数,也叫方法
self.name=None #属性值为空
self.score=None #属性值为空
def print_score(self):
print("%s score is %s"% (self.name,self.score))
s1=Game() #创建对象1
s1.name='Tom'
s1.score=8
s2=Game() #创建对象2
s2.name='Jerry'
s2.score=7
s1.print_score()
s2.print_score()
>>>
Tom score is 8 #输出结果
Jerry score is 7
这种形式在定义方法时,就直接给定了两个参数name和score,且属性值不允许为空。实例化时,直接传入参数。
class Game: #定义类Game
def __init__(self,name,score): #创建类中的函数,也叫方法
self.name=name #属性值不为空
self.score=score #属性值不为空
def print_score(self):
print("%s score is %s"% (self.name,self.score))
s1=Game("tom",8) #创建对象s1
s2=Game("Jerry",7) #创建对象s2
s1.print_score()
s2.print_score()
>>>
tom score is 8
Jerry score is 7
总结:
1、self是形式参数,当执行s1 = Game(“Tom”, 8)时,self等于s1;当执行s2 = Game(“sunny”, 7)时,self=s2。
2、两种方法的区别在于定义函数时属性赋值是否允许为空和实例化时是否直接传入参数,个人觉得第二种更为简洁。
class类内容的基本组成:
(1)类属性:类中所涉及的变量
(2)类方法:类中的函数
2、init()函数解析
(1)双下划线开头的函数为私有函数,不能在类的外部被调用或直接访问;
(2)init(),支持带参数的初始化,例如:def init(self,ai_settings,screen):
(3)init()函数的第一个参数必须为self(也可是别的名字),后续参数可自由指定;
class中函数的定义
基本形式如下:
def 函数名(参数1,参数2....):
(1)在类的内部,使用def关键字定义一个函数必须包含参数self且必须为第一个参数,也可用**kw定义关键参数(表示任意参数)。
(2)self只有在类的方法中才会有,独立函数或者方法是不必须带self的,self名称不是必须的,是人们约定成俗的,self指的是类实例对象本身,而不是类本身。
# 不用init()方法定义类
# 定义一个矩形的类,目的是求周长和面积
class Rectangle():
def getPeri(self,a,b):
return (a+b)*2
def getArea(self,a,b):
return a*b
rect=Rectangle()
print(rect.getPeri(3,4))
print(rect.getArea(3,4))
print(rect.__dict__)
>>>
14
12
{}
class Rectangle():
def __init__(self,a,b):
self.a=a
self.b=b
def getPeri(self):
return (self.a + self.b)*2
def getArea(self):
return self.a * self.b
rect = Rectangle(3,4)
print(rect.getPeri())
print(rect.getArea())
print(rect.__dict__)
>>>
14
12
{'a': 3, 'b': 4}
从上例中可以看到,我们在类中并没有定义init()方法,但是也能够得到类似的要求,结果返回了矩形实例rect的周长及面积。
但是,我们通过print(rect.dict)来看这个实例的属性,竟然是空的,我定义了一个矩形,按理来说它的属性应该是它的长、宽。但是它竟然没有。这就是没有定义init()的原因了。
并且,在实例化对象的时候,rect = Rectangle()参数为空,没有指定a、b的值,只有在调用函数的时候才指定了。且类中定义的每个方法的参数都有a、b,这显然浪费感情,在类中直接指定方法就可以了。、
因此吧,需要在类中定义init()方法,方便创建实例的时候,需要给实例绑定上属性,也方便类中的方法(函数)的定义。
定义完init()后,创建的每个实例都有自己的属性,也方便直接调用类中的函数。