python 单一继承定义_Python-面向对象之单继承

、基本概念

面向对象三要素之一:继承inheritance

继承表达式:class Cat(Anaimal),继承可以让子类从父类获取特征(属性和方法)

父类:Anaimal 就是Cat的父类,也称为基类,超类

子类:Cat就是Anaimal的子类,也称为派生类

2、定义

格式如下:

class子类名(父类名):

语句块

如果类定义时,没有基类列表,等同于继承自object,在Python3中,object类是所有对象的根基类

只在python3 中是可以等价的,python2中不同的

classA:pass等同于classA(object):pass

注意:python支持多继承,继承也可以多级。

查看继承的特殊属性和方法有:

特殊属性和方法

含义

示例

__base__

类的基类

__bases__

类的基类元组

__mor__

显示方法查找顺序,基类的元组

mro()方法

同上,返回列表

__subclassedd__()

类的子类列表

print(Anaimal.__subclasses__())

3、继承中的访问控制:

举例:

1 classAnaimal:2 __COUNT = 100

3 HEIGHT =04

5 def __init__(self, age, weight, height):6 self.__COUNT += 1

7 self.age =age8 self.__weight =weight9 self.HEIGHT =height10

11 defeat(self):12 print('{} eat'.format(self.__class__.__name__))13

14 def __getweight(self):15 print(self.__weight)16

17 @classmethod18 defshowcount1(cls):19 print(cls)20 print(cls.__dict__)21 print(cls.__COUNT)22

23 @classmethod24 def __showcount2(cls):25 print(cls.__COUNT)26

27 defshowcount3(self):28 print(self.__dict__)29 print(self.__COUNT)

t1.py

1 from t1 importAnaimal2

3 classCat(Anaimal):4 NAME = 'CAT'

5 __COUNT = 200

6

7 #c = Cat() 缺参数,报错

8 c = Cat(3, 5, 15)#使用父类初始化函数进行初始化

9 #print(c.HEIGHT) # 自己没有,调用父类的属性

10 #c.eat()# 调用父类的方法

11 #print(c._Anaimal__weight)# 获取父类初始化函数中的属性

12 #c._Anaimal__getweight()

13

14 c.showcount3()

t2.py

总结:

从父类继承,自己没有的,就可到父类中找

私有的都是不可以访问的,但是本质上依然是改了名称放在这个属性所在类或示例的__dict__中,知道这个名称就可以直接找到这个隐藏的变量,这个是黑魔法,慎用

继承时,公有的,子类和实例都可以随意访问,私有成员被隐藏,子类和实例不可直接访问,但私有变量所在的类内的方法可以访问这个私有变量

Python通过自己一套实现,实现和其他语言一样的面向对象的继承机制

私有的只个自己用,并不是给其他的类或实例用的,出去的,也就是可以直接在类外调用的,都是共有的

事实上,在类内部是可以随便访问的,直接  .__xx 调用的,但事实上,在外部,看到的不是这个名字

如果想获取私有属性,可以给一个调用方法 如:getage 返回 self.__age,或者使用属性装饰器property,从而不需要知道隐藏属性的真是名称,直接访问

私有方法,就不要调来调去了,虽然是可以的!

属性查找顺序:

实例的__dict__ ----> 类的 __dict__ ---> 如果有继承 -----> 父类的__dict__

如果一直没找到,抛异常,找到了,立即返回

4、方法的重写、覆盖override

举例:

1 classAnaimal:2 defshout(self):3 print('Animal')4

5 classCat(Anaimal):6 defshout(self):7 print(super())8 print(super(Cat, self))9 super().shout()10 super(Cat, self).shout()11 self.__class__.__base__.shout(self)12 print('miao')13

14 #a = Anaimal()

15 #a.shout()

16 c =Cat()17 c.shout()18 #print(a.__dict__)

19 #print(c.__dict__)

20 #print(Anaimal.__dict__)

21 #print(Cat.__dict__)

举例

对于类方法和静态方法也是一样的:

1 classAnimal:2 @classmethod3 defclass_method(cls):4 print('class_Animal')5

6 @staticmethod7 defstatic_method():8 print("static_Animal")9

10 class Cat(Animal):pass

11 #@classmethod

12 #def class_method(cls):

13 #print('class_Cat')

14 #15 #@staticmethod

16 #def static_method():

17 #print("static_Cat")

18

19 c =Cat()20 c.class_method()21 c.static_method()

5、继承中的初始化

举例:

从上面的代码可以看出:

如果类B 定义时声明继承 类A,则在类B 中__bases__中是可以看到类A的,但是这和是否调用类A 的构造方法时两回事

如果B中调用了A 的构造方法,就可以拥有父类的属性了,

举例:

1 classA:2 def __init__(self, a, d=10):3 self.__d =d4 self.a =a5

6 classB(A):7 def __init__(self, b, c):8 super().__init__(b+c, b-c)9 #等价 A.__init__(self, b+c, b-c)

10 self.b =b11 self.c =c12

13 defprintv(self):14 print(self.b)15 print(self.a)16 print(self._A__d)17

18 f = B(200, 300)19 print(f.__dict__)20 print(f.__class__.__bases__)21 f.printv()

View Code

总结:

作为好习惯,如果分类定义了__init__方法,要在子类的__init__中调用它。显式的调用

除非:子类没有定义__init__,会隐式去调用或者继承父类的__init__,子类一旦定义了__init__,就不会自动调用父类的init

如何正确的初始化:

1 classAnimal:2 def __init__(self, age):3 print('Animal')4 self.age =age5

6 defshow(self):7 print(self.age)8

9 classCat(Animal):10 def __init__(self, age, weight):#没有调用父类的init,这就导致没有实现继承效果

11 print('Cat')12 self.age = age + 1

13 self.weight =weight14

15 c = Cat(10, 5)16 print(c.__dict__)17 c.show()18

19 print('-' * 30)20 classAnimal:21 def __init__(self, age):22 print('Animal')23 self.age =age24

25 defshow(self):26 print(self.age)27

28

29 classCat(Animal):30 def __init__(self, age, weight):31 print('Cat')32 super().__init__(age)33 self.age = age + 1 #覆盖之前的self.age

34 self.weight =weight35

36

37 c = Cat(10, 5)38 print(c.__dict__)39 c.show()40

41

42 print('-' * 30)43 classAnimal:44 def __init__(self, age):45 print('Animal')46 self.age =age47

48 defshow(self):49 print(self.age)50

51

52 classCat(Animal):53 def __init__(self, age, weight):54 print('Cat')55 self.age = age + 1

56 self.weight =weight57 super().__init__(age)58

59

60 c = Cat(10, 5)61 print(c.__dict__)62 c.show()

注意init出现的位置

1 Cat2 {'age': 11, 'weight': 5}3 11

4 ------------------------------

5 Cat6 Animal7 {'age': 11, 'weight': 5}8 11

9 ------------------------------

10 Cat11 Animal12 {'age': 10, 'weight': 5}13 10

结果打印

例子中打印10 的,原因看__dict__ 就知道了,因为父类Animal的show方法中_age会被释放为_Animal__age,因此。显式10,而不是11,这样的设计不会,子类应该显式自己的属性值最好

解决办法:

一个原则,自己的私有属性,就该自己的方法读取和修改,不要借助其他类的方法,即使是父类或者派生类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值