Python中的面向对象编程详解(下)

本文讲解了继承、super关键字、重写、多重继承、类、实例和其他对象的内建函数、私有化等内容。
继承
继承描述了基类的属性如何“遗传”给派生类。一个子类可以继承它的基类的任何属性,不管是数据属性还是方法。 
创建子类的语法看起来与普通(新式)类没有区别,一个类名,后跟一个或多个需要从其中派生的父类:

示例:

class Parent(object): #定义父类
    def parentMethod(self):
        print 'calling parent method'

class Child(Parent): # 定义子类
    def childMethod(self):
        print 'calling child method'

p=Parent()
c=Child()
p.parentMethod()
c.childMethod()
继承与覆盖
继承
python的子类继承父类后,会把父类的所有的方法,包括构造器init()也继承下来.

class Parent():
    def __init__(self):
        print "init Parent class instance"
    
    def func(self):
        print "call parent func"

class Child(Parent):
    pass

child = Child()#由于Child类没有定义自己的__init__方法,因此,此处调用的是父类的__init__方法
child.func()#同理,子类没有定义自己的func方法,此处调用的是父类的func方法
运行结果:
init Parent class instance
call parent func
super关键字
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,
会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
super继承只能用于新式类,用于经典类时就会报错。 
新式类:继承链开始于object类
经典类:父类没有继承object类,如果此时调用super就会出现错误:『super() argument 1 must be type, not classobj』
示例

class Parent(object):#新式类
    def __init__(self):
        self.phone = '123456'
        self.address = 'abcd'

class Child(Parent):
    def __init__(self):
        #Parent.__init__(self)#采用这种方式调用父类的构造函数不要求继承链开始于object类
        super(Child, self).__init__()#super方法要求继承链开始于object类
        self.data = 100

def main():
    child = Child()
    print "phone is:", child.phone
    print "address is:", child.address
    print "data is:", child.data

if __name__ == '__main__':
    main()
运行结果:
phone is: 123456
address is: abcd
data is: 100
重写:子类只要重新定义一个与父类的方法同名的方法,就可以重写覆盖父类的方法。

class Parent():
    def __init__(self):
        print "init Parent class instance"
    def func(self):
        print "call parent func"
        
class Child(Parent):
    def __init__(self):#重写__init__方法
        print "init Child class instance"
    def func(self):#重写func方法
        print 'call Child func'

child = Child()
child.func()
运行结果:
init Child class instance
call Child func
多重继承
同 C++ 一样,Python 允许子类继承多个基类。但一般不推荐用多重继承。
经典类的多重继承

class A():#经典类:继承链没有开始于object类,搜索时按照 深度优先 搜索方式
    def __init__(self):
        print "A.__init__ is called!"

class B(A):
    pass

class C(A):
    def __init__(self):
        print 'C.__init__ is called!'

class D(B,C):
    pass

d=D()
运行结果:
A.__init__ is called!
因为按照深度优先搜索,所以调用的是类A的构造方法。
新式类的多重继承

class A(object):#新式类:继承链开始于object类,搜索时按照 广度优先 搜索方式
    def __init__(self):
        print "A.__init__ is called!"

class B(A):
    pass

class C(A):
    def __init__(self):
        print 'C.__init__ is called!'

class D(B,C):
    pass

d=D()

运行结果:
C.__init__ is called!
因为按照广度优先搜索,所以调用的是类C的构造方法。

类、实例和其他对象的内建函数
issubclass()
布尔函数 判断一个类是另一个类的子类或子孙类。
class A(object):
    pass
class B(A):
    pass
class C(B):
    pass

print issubclass(A,object) # True
print issubclass(C,object) # True
print issubclass(B,A)      # True
print issubclass(C,B)      # True
print issubclass(C,B)      # True
attr()系列函数
hasattr():它的作用是判断一个对象是否有一个特定的属性,一般用于访问某属性前先作一下检查。
getattr()和setattr() :这2个函数分别是获得和赋值给对象的属性,
delattr() :删除特定的属性

class Parent(object):
    pass

class Child(Parent):
    def __init__(self):
        self.data = 100

child = Child()
print "child has data attr?", hasattr(child, 'data')
print 'child.data=',child.data
print "delete data attr of child"
delattr(child, 'data')
print "child has data attr?", hasattr(child, 'data')
# print 'child.data=',child.data #已经将data属性删除,因此报错:AttributeError
print "set data attr to 200 for child"
setattr(child, 'data', 200)
print 'child has data attr?',hasattr(child,'data')
print "child.data=", getattr(child, 'data')
运行结果:
child has data attr? True
child.data= 100
delete data attr of child
child has data attr? False
set data attr to 200 for child
child has data attr? True
child.data= 200

私有化
Python没有像Java那样实现真正的封装,只是用双划线和单划线实现私有化.
双划线:防止外部访问.如在func前加双划线,可以防止实例(包括子类的实例)的访问.
class A():
    def __func(self):#私有方法:外界(实例以及子类的实例)不可调用
        print 'A.__func is called!'
    def func(self):
        self.__func()
class B(A):
    pass

a=A()
#a.__func() #私有方法,外界不可访问 :AttributeError
a.func() # 先调用公有方法func,通过公有方法去调用私有方法__func
b=B()
#b.__func() #私有方法,外界不可访问 :AttributeError
b.func() # 先调用公有方法func,通过公有方法去调用私有方法__func
运行结果:
A.__func is called!
A.__func is called!

单划线:防止模块的属性用“from mymodule import *”来加载。
在同一个python package中新建2个python文件:kk.py和test_kk.py
kk.py文件:
class _A():
    def __init__(self,name):
        self.name=name

def _func():
    print 'func is called!'
test_kk.py文件的内容:

from kk import * #这种方式无法加载  用单划线私有化的模块属性
_func() #NameError: name '_func' is not defined
a=_A('python') #NameError: name '_A' is not defined
print a.name
print getattr(a,'name')
修改test_kk.py文件的内容:

from kk import _func,_A #可以通过这种方式导入 用单划线私有化的模块属性
_func() 
a=_A('python')
print a.name
print getattr(a,'name')
运行结果:
func is called!
python
python

也修改test_kk.py文件的内容如下:

import kk #也可以通过这种方式 导入 用单划线私有化的模块属性
kk._func() 
a=kk._A('python') 
print a.name
print getattr(a,'name')
运行结果:
func is called!
python
python
综上所述:用单划线私有化的模块属性 无法用“from mymodule import *”来加载,可以用其它两种加载方式。。。


原文链接:点击打开链接


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值