博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

二、Python开发---16、继承和多态

Posted on 2019-10-12 19:10  兰智杰  阅读(220)  评论(0编辑  收藏  举报

继承和多态

  程序中当定义一个class的时候,可以从某个现有的class继承,新的class称之为子类(Subclass),而被继承的class称之为基类、父类或超类;子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法

class Animal():
    def __init__(self,name,food):
        self.name = name
        self.food = food
    def eat(self):
        print('%s爱吃%s'%(self.name,self.food))

#声明一个子类继承animal
class Dog(Animal):
    def __init__(self,name,food,drink):
        #加载父类构造方法(两种可以任选其中一种)
        #Animal.__init__(self,name,food)
        super(Dog, self).__init__(name,food)
        self.drink = drink                              #子类自己的属性
    def drinks(self):                                   #子类自己的方法
        print('%s爱喝%s'%(self.name,self.drink))

class Cat(Animal):
    def __init__(self,name,food,drink):
        # 加载父类构造方法(两种可以任选其中一种)
        Animal.__init__(self,name,food,)
        #super(Cat, self).__init__(name,food)
        self.drink = drink                              #子类自己的属性
    def drinks(self):                                   #子类自己的方法
        print('%s爱喝%s'%(self.name,self.drink))
    #重写父类的eat
    def eat(self):
        print('%s特别爱吃%s'%(self.name,self.food))

dog1 = Dog('金毛','骨头','可乐')
dog1.eat()                                              #输出为 金毛爱吃骨头
dog1.drinks()                                           #输出为 金毛爱喝可乐

cat1 = Cat('波斯猫','秋刀鱼','雪碧')
cat1.eat()                                              #输出为 波斯猫特别爱吃秋刀鱼
cat1.drinks()                                           #输出为 波斯猫爱喝雪碧

多继承

  需要注意子类调用父类时,圆括号中父类的顺序,如果继承的父类中有相同的方法名, 而在子类中使用时未指定,python将从左至右查找父类中是否包含方法

class A():
    def __init__(self, mid,jungle):
        self.jungle = jungle
        self.mid = mid
    def a(self):
        print('我是skt的中单%s' %self.mid)

class B():
    def __init__(self, ad, sub):
        self.ad = ad
        self.sub = sub
    def b(self):
        print('我是skt的射手%s' % self.ad)
    def a(self):
        print('我是skt的替补%s' % self.sub)

class C():
    def c(self):
        print('我是skt的教练kkoma')
'''
    需要注意圆括号中父类的顺序,如果继承的父类中有相同的方法名,
    而在子类中使用时未指定,python将从左至右查找父类中是否包含方法
'''
class D(A,B,C):
    def __init__(self,mid,jungle,ad,sub):
        #加载父类构造方法(两种可以任选其中一种)
        # A.__init__(self, mid,jungle)           #init A
        # B.__init__(self, ad, sub)              #init B
        super(D, self).__init__(mid,jungle)      #init A     注意里面是D,但加载的却是A
        super(A, self).__init__(ad, sub)         #init B     注意里面是A,但加载的却是B

d = D('faker','bengi','bang','blank')
d.a()                                            #输出为   我是skt的中单faker    这里调用的a()是A中的方法
d.c()                                            #输出为   我是skt的教练kkoma
d.b()                                            #输出为   我是skt的射手bang

class E(B,A,C):                                  #不同于D中的顺序,这里为B,A,C
    def __init__(self,mid,jungle,ad,sub):
        #加载父类构造方法(两种可以任选其中一种)
        # A.__init__(self, mid,jungle)           #init A
        # B.__init__(self, ad, sub)              #init B
        super(E, self).__init__(mid,jungle)      #init A     注意里面是E,但加载的却是B
        super(B, self).__init__(ad, sub)         #init B     注意里面是B,但加载的却是A

e = E('bang','blank','faker','bengi')
e.a()                                            #输出为   我是skt的替补blank    这里调用的a()是B中的方法
e.c()                                            #输出为   我是skt的教练kkoma
e.b()                                            #输出为   我是skt的射手bang

类属性和实例属性

  1、实例属性:

    在__init__(self,...)中初始化,内部调用时都需要加上self,外部调用时用“对象名.属性名”调用

  2、类属性:

    在__init__()里初始化,在内部用类名.类属性名调用,外部既可以用类名.类属性名(推荐这种方式)又可以用对象名.类属性名来调用

  3、私有属性:

    双下划线__开头,外部不可通过“对象名.属性名”来访问,可以通过“_类名__属性名”强制访问

单下划线、双下划线、头尾双下划线说明

  1、__foo__:定义的是特殊方法,类似 __init__()之类的

  2、_foo:以单下划线开头的表示的是保护类型的变量,即保护类型只能允许其本身与子类进行访问(创建的实例可以访问),而不能够

  用于from module import * 

  3、__foo:双下划线的表示的是私有类型的变量, 只能是允许这个类本身进行访问了

访问限制——私有属性

  1、为了保护属性不被随意修改和访问,可以将属性定义为私有属性;如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例变量名如果以__开头,就变成了一个私有变量,只有内部可以访问,外部不能访问

  2、设置为私有属性不能直接通过对象访问属性,但是可以通过“实例化对象名._类名__属性名”直接进行访问和修改;但是不建议这样操作,不同版本的Python解释器可能会把“__属性名”改成不同的变量名,总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉

  3、通过“对象名.__属性名”直接修改私有属性,表面上看好像修改了其实并没有,因为Python解释器已经将对象内部的属性名解释成“_类名__属性名”,如果在外部修改相当于另外声明一个属性

class person():
    country = '中国'                                 #声明类属性,并且赋值
    def __init__(self,name,age,sex,address):        #构造方法,实例属性通过构造方法来声明
        self.name = name                            #通过self创建实例属性,并且赋值   self不是关键字
        self.age = age
        self.sex = sex
        self.__address = address                    #双下划线开头的属性是私有属性

    def getName(self):                              #创建普通方法
                                                    #类属性的使用通过类名.属性名使用 这是规范
                                                    #私有属性在类里面使用正常使用
        print('我的名字叫:%s,我来自%s,我住在%s'%(self.name,person.country,self.__address)) #在方法里面使用实例属性

    #外部要修改私有属性  预留一个接口去访问或者修改私有属性  这个就是正确的打开方式
    def getAddre(self,pwd):
        if pwd == '123':
            return self.__address
        else:
            return '权限不够'

people01 = person('joe',19,'','上海')              #实例化对象
people01.getName()                                  #输出为我的名字叫:joe,我来自中国,我住在上海
                                                    #通过对象名.属性名访问私有属性
#print(people01.__address)                          #系统报错  因为外部无法使用这种方式访问
print(people01.getAddre('1234'))                    #输出为 权限不够
print(people01._person__address)                    #强制访问,不建议这么做  输出为上海
people01.__address = '北京'                          #看上去好像改了,其实没有  相当于给当前对象声明了一个新属性
print(people01.__address)                           #输出为北京
print(people01.getAddre('123'))                     #输出为上海
people01._person__address = '南京'                   #强制修改,不建议这么做
print(people01.getAddre('123'))                     #输出为南京

类方法和静态方法

  1、普通方法:

    def  fun_name(self,...):

      pass

    外部用实例调用

  2、静态方法:通过装饰器 @staticmethod 装饰,不能访问实例属性,参数不能传入self,静态方法只能访问类属性

  3、类方法:@classmethod,不能访问实例属性,参数必须传入cls,必须传入cls参数(即代表了此类对象-----区别------self代表实例对象),并且用此来调用类属性:cls.类属性名

  静态方法与类方法都可以通过类或者实例来调用,其两个的特点都是不能够调用实例属性,静态方法不需要接收参数,使用类名.类属性,说白了静态方法与类方法都是针对类属性的,

class person():
    country = '中国'                                      #声明类属性,并且赋值
    #实例属性通过构造方法来声明
    #self不是关键字,代表的是当前对象
    def __init__(self,name,age,sex,address,country):     #构造方法
        #构造方法不需要调用,在实例化的时候自动调用
        self.name = name                                 #通过self创建实例属性,并且赋值
        self.age = age
        self.sex = sex
        self.__address = address                         #双下划线开头的属性是私有属性
        person.country = country                         #类属性的申明,一般不用这种方式
    #创建普通方法
    def getName(self):
        #类属性的使用通过类名.属性名使用 这是规范
        #私有属性在类里面使用正常使用
        print('我的名字叫:%s,我来自%s,我住在%s'%(self.name,person.country,self.__address)) #在方法里面使用实例属性
    #创建一个静态方法
    @staticmethod
    def aa():                                           #不需要传递实例
        #静态方法不能访问实例属性
        #静态方法只能访问类属性
        print('我的名字叫:%s'% person.country)           #在方法里面使用实例属性
    #类方法
    @classmethod
    def bb(cls,n):                                      #cls  也不是关键字
        #类方法不能访问实例属性
        cls.country = n
        print('我的名字叫:%s' %cls.country )             #就用cls.类属性

#实例化对象
people01 = person('joe',19,'','上海','中国')
#通过对象来调用静态方法
#people01.aa()
#通过对象来调用类方法
#people01.bb('usa')
people01.getName()                                      #输出为 我的名字叫:joe,我来自美国,我住在上海
#静态方法和类方法的调用,推荐使用类名的方式去调用
#通过类名来调用静态方法
people01.aa()                                           #输出为 我的名字叫:中国
#通过类名来调用类方法
person.bb('usa')                                        #输出为 我的名字叫:usa