首页 > 代码库 > Python interview - override & overload

Python interview - override & overload

我们先说overload 重载。


在Java中,支持重载,重载的意思是能够定义有相同方法名的方法,传入方法中的参数个数,或者参数类型不同。比如:

int mymethod(int a, int b)
int mymethod(int num)

float mymethod(int a, float b)
float mymethod(float var1, int var2)

int mymethod(int a, int b)
int mymethod(float var1, float var2)

如下的例子是错误的,因为传入的参数个数相同,类型相同,仅仅给了一个不同的命名并不改变具体的方法。

int mymethod(int a, int b, float c)
int mymethod(int var1, int var2, float var3)

那么对于python,我们也可以写出这样的方法,举例来说明为什么python不支持overload

def sum(a,b):
   return a+b

def sum(a,b,c):
   return a+b+c

上述的方法,如果python支持overload,我们运行两个不同的sum方法的时候,会得到不同的结果

print sum(1,2)
print sum(1,2,3)

# result

TypeError: sum() takes exactly 3 arguments (2 given)

当我们想调用第一个sum方法的时候报错。这是因为python不支持overload,第二个同名的方法会覆盖overwrite第一个方法。

所以,当我们想在python中运用类似overload的技巧的时候,更多的我们会使用

default argument values

def ask_ok(prompt, retries=4, complaint='Yes or no, please!')
你可以调用这个方法,传入不同个数的参数

ask_ok('Do you really want to quit?')
ask_ok('OK to overwrite the file?', 2)
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

keyword arguments

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
如果使用的keyword赋值,那么不需要按照顺序传入参数

parrot(1000)                                          # 1 positional argument
parrot(voltage=1000)                                  # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword

arbitrary argument lists

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))


####################################################################################################################################


我们接着说python的override重写

在Java中,我们用extends 父类方法来继承,继承父类的方法,并可以重写方法中的内容。同时可以用super关键词调用父类的方法。

Python中可以做同样的事,没有extends,有super。

class Parent(object):
    def myMethod(self):
        print 'Calling parent method'


class Child(Parent):
    def myMethod(self):
        print 'Calling child method'


p = Parent()
p.myMethod()
c = Child()
c.myMethod()

# result

Calling parent method
Calling child method

Child继承了Parent类,重写了myMethod方法。当然也可以不继承myMethod方法,随便自己写自己的方法。

但是继承了之后,可以使用super关键词来调用父类的方法

class Parent(object):
    def myMethod(self):
        print 'Calling parent method'


class Child(Parent):
    def childMethod(self):
        print 'Calling child method'
        super(Child, self).myMethod()


p = Parent()
p.myMethod()
c = Child()
c.childMethod()

# result

Calling parent method
Calling child method
Calling parent method

同样的代码,加入了super关键词,就等于在调用childMethod方法的时候,会再调用父类的myMethod方法。


####################################################################################################################################


扩展


1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。有别于C#
2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

class BaseClass:    def __init__(self, name, age):        self.name = name        self.age = age        print "baseclass is inited"    def speak(self, name):        print "base class is speaking: %s" % nameclass SubClass(BaseClass):    def __init__(self, name, age, salary):        BaseClass.__init__(self, name, age)# 调用父类函数要记得带上self,区别普通调用不需要self        self.salary=salary        print "SubClass is inited and the salary is: %s" % self.salary    def talk(self, sth):        print "%s talking: %s" % (self.name, sth)        BaseClass.speak(self, sth) <span style="font-family: Arial, Helvetica, sans-serif;"># 调用父类函数要记得带上self,区别普通调用不需要self</span>if(__name__=="__main__"):    s=SubClass("Joan",1,800)    s.talk("a story")# resultbaseclass is initedSubClass is inited and the salary is: 800Joan talking: a storybase class is speaking: a story

假如子类中不用__init__初始化函数,那么子类会继承父类的属性

class BaseClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print "baseclass is inited"
    def speak(self, name):
        print "base class is speaking: %s" % name

class SubClass(BaseClass):
    #def __init__(self, name, age, salary):
    #    BaseClass.__init__(self, name, age)
    #    self.salary=salary
    #    print "SubClass is inited and the salary is: %s" % self.salary
    def talk(self, sth):
        print "%s talking: %s, his age is %d" % (self.name, sth, self.age)
        BaseClass.speak(self, sth)
if(__name__=="__main__"):
    s=SubClass("Joan",1)# 初始化的时候,会先在本类中调用init方法,没有就调用父类的
    s.talk("a story")
    s.speak("directly use baseclass function") # 通过子类调用speak方法,会先在子类中查找,找到就直接调用,找不到就会寻找父类中调用

# result

baseclass is inited
Joan talking: a story, his age is 1
base class is speaking: a story
base class is speaking: directly use baseclass function

当我们注释了子类的__init__方法之后,就会继承父类的属性。


多重继承

class P1 #(object): 
   def foo(self):           
       print 'p1-foo' 
 
class P2 #(object): 
   def foo(self): 
       print 'p2-foo' 
   def bar(self): 
       print 'p2-bar' 
 
class C1 (P1,P2): 
   pass  
 
class C2 (P1,P2): 
   def bar(self): 
       print 'C2-bar'   
 
class D(C1,C2): 
   pass 

注意到上述代码中,我们注释了class继承object,这类属于经典类,我们来调用函数

d = D()
d.foo()
d.bar()

# result

p1-foo
p2-bar

实例d调用foo()时,搜索顺序是 D => C1 => P1

实例d调用bar()时,搜索顺序是 D => C1 => P1 => P2

换句话说,经典类的搜索方式是按照“从左至右,深度优先”的方式去查找属性。d先查找自身是否有foo方法,没有则查找最近的父类C1里是否有该方法,如果没有则继续向上查找,直到在P1中找到该方法,查找结束。



当我们把object的注释取消掉之后,运行同样的代码

class P1 (object):   def foo(self):       print 'p1-foo'class P2 (object):   def foo(self):       print 'p2-foo'   def bar(self):       print 'p2-bar'class C1 (P1,P2):   passclass C2 (P1,P2):   def bar(self):       print 'C2-bar'class D(C1,C2):   passd = D()d.foo()d.bar()print "MRO:", [x.__name__ for x in D.__mro__]# resultp1-fooC2-barMRO: ['D', 'C1', 'C2', 'P1', 'P2', 'object']

如上所述,我们得到不同的结果。

实例d调用foo()时,搜索顺序是 D => C1 => C2 => P1

实例d调用bar()时,搜索顺序是 D => C1 => C2

可以看出,新式类的搜索方式是采用“广度优先”的方式去查找属性。


我们可以使用__mro__属性来查看查找顺序。



参考:

http://beginnersbook.com/2013/05/method-overloading/

http://forums.udacity.com/questions/20750/method-overloading-in-python

https://docs.python.org/2/tutorial/controlflow.html#more-on-defining-functions

http://2577885.blog.51cto.com/2567885/669322

http://blog.csdn.net/seizef/article/details/5310107

http://www.cnblogs.com/Joans/archive/2012/11/09/2757368.html


Python interview - override & overload