浅谈Python类的单继承相关知识

一、类的继承

面向对象三要素之一,继承Inheritance

人类和猫类都继承自动物类。

个体继承自父母,继承了父母的一部分特征,但也可以有自己的个性。

在面向对象的世界中,从父类继承,就可以直接拥有父类的属性和方法,这样就可以减少代码、多服用。子类可以定义自己的属性和方法

class Animal:

    def __init__(self,name):
        self._name = name

    def shout(self):
        print("{}  shouts".format(self.__class__.__name__))
    @property
    def name(self):
        return self._name

class Cat(Animal):
    pass

class Dog(Animal):
    pass

a = Animal("monster")
a.shout()           #   Animal  shouts

cat = Cat("garfield")
cat.shout()         #   Cat  shouts
print(cat.name)     #   garfield

dog = Dog("ahuang")
dog.shout()         #   Dog  shouts
print(dog.name)     #   ahuang

上例中我们可以看出,通过继承、猫类、狗类不用写代码,直接继承了父类的属性和方法

继承:

  • class Cat(Animal)这种形式就是从父类继承,括号中写上继承的类的列表。
  • 继承可以让子类重父类获取特征(属性、方法)

父类:

  • Animal就是Cat的父类,也称为基类、超类

子类:

  • Cat 就是Animal的子类,也成为派生类

二、继承的定义、查看继承的特殊属性和方法

格式

class 子类 (基类1[,基类2,……]):
    语句块

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

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

特殊属性  含义 示例
__base__  类的基类 
__bases__  类的基类元组 
__mro__  显示方法查找顺序,基类的元组 
mro()  同上  int.mro()
__subclasses__()  类的子类列表  int.__subclasses__()

三、继承中的访问控制

class Animal:
    __COUNT = 100
    HEIGHT = 0

    def __init__(self,age,weight,height):
        self.__COUNT += 1
        self.age = age
        self.__weight = weight
        self.HEIGHT = height

    def eat(self):
        print("{}  eat".format(self.__class__.__name__))

    def __getweight(self):
        print(self.__weight)

    @classmethod
    def showcount1(cls):
        print(cls.__COUNT)

    @classmethod
    def __showcount2(cls):
        print(cls.__COUNT)

    def showcount3(self):
        print(self.__COUNT)

class Cat(Animal):
    NAME = "CAT"
    __COUNT = 200

#a = Cat()              #   TypeError: __init__() missing 3 required positional arguments: 'age', 'weight', and 'height'
a = Cat(30,50,15)
a.eat()                 #   Cat  eat
print(a.HEIGHT)         #   15
#print(a.__COUNT)        #   AttributeError: 'Cat' object has no attribute '__COUNT'
#print(a.__showcount2)   #   AttributeError: 'Cat' object has no attribute '__showcount2'
#print(a.__getweight)    #   AttributeError: 'Cat' object has no attribute '__getweight'
a.showcount3()   #   101
a.showcount1()   #  100
print(a.NAME)    #    CAT

print(Animal.__dict__)  #   {'__module__': '__main__', '_Animal__COUNT': 100, 'HEIGHT': 0, '__init__': <function Animal.__init__ at 0x020DC228>, 'eat': <function Animal.eat at 0x020DC468>, '_Animal__getweight': <function Animal.__getweight at 0x02126150>, 'showcount1': <classmethod object at 0x020E1BD0>, '_Animal__showcount2': <classmethod object at 0x020E1890>, 'showcount3': <function Animal.showcount3 at 0x021264F8>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}
print(Cat.__dict__)     #   {'__module__': '__main__', 'NAME': 'CAT', '_Cat__COUNT': 200, '__doc__': None}
print(a.__dict__)       #   {'_Animal__COUNT': 101, 'age': 30, '_Animal__weight': 50, 'HEIGHT': 15}

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

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

总结

  • 继承时,共有的,子类和实例都可以随意访问;私有成员被隐藏,子类和实例不可直接访问,当私有变量所在类内方法中可以访问这个私有变量
  • Python通过自己一套实现,实现和其他语言一样的面向对象的继承机制

属性查找顺序:实例的【__dict__】------类的【__dict__】-----父类【__dict__】

如果搜索这些地方后没有找到异常,先找到就立即返回

四、方法的重写、覆盖override

class Animal:

    def shout(self):
        print("Animal shouts")

class Cat(Animal):

    def shout(self):
        print("miao")

a = Animal()
a.shout()       #   Animal shouts
b  = Cat()
b.shout()       #   miao

print(a.__dict__)       #   {}
print(b.__dict__)       #   {}
print(Animal.__dict__)  #   {'__module__': '__main__', 'shout': <function Animal.shout at 0x017BC228>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}

Cat类中shout为什么没有打印Animal中shout的方法,方法被覆盖了?

  • 这是因为,属性查找顺序:实例的【__dict__】------类的【__dict__】-----父类【__dict__】

那子类如何打印父类的同命的方法

  • super()可以访问到父类的属性
class Animal:

    def shout(self):
        print("Animal shouts")

class Cat(Animal):

    def shout(self):
        print("miao")

    def shout(self):
        print("super():   " , super())
        print(super(Cat, self))
        super().shout()
        super(Cat,self).shout()   # 等价于super().shout()
        self.__class__.__base__.shout(self)  #不推荐使用

a = Animal()
a.shout()       #   Animal shouts
b  = Cat()
b.shout()       #   super():    <super: <class 'Cat'>, <Cat object>>
                #   <super: <class 'Cat'>, <Cat object>>
                #   Animal shouts
                #   Animal shouts
                #   Animal shouts
print(a.__dict__)       #   {}
print(b.__dict__)       #   {}
print(Animal.__dict__)  #   {'__module__': '__main__', 'shout': <function Animal.shout at 0x019AC228>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}
print(Cat.__dict__)     #   {'__module__': '__main__', 'shout': <function Cat.shout at 0x019F6150>, '__doc__': None}

super(Cat,self).shout()的作用相当于

  • 调用,当前b的实例中找cat类基类中,shout的方法

那对于类方法和静态方法是否也同样适用尼?

class Animal:
    @classmethod
    def class_method(cls):
        print("class_method")

    @staticmethod
    def static_method():
        print("static_methond_animal")

class Cat(Animal):
    @classmethod
    def class_method(cls):
        super().class_method()  #   class_method
        print("class_method_cat")

    @staticmethod
    def static_method(cls,self):
        super(Cat,self).static_method()
        print("static_method_cat")

b = Cat()
b.class_method()    #   class_method
                    #   class_method_cat
b.static_method(Cat,b)
                    #   static_methond_animal
                    #   static_method_cat

这些方法都可以覆盖,原理都一样,属性字典的搜索顺序

五、继承中的初始化

看以下一段代码,有没有问题

class A:
    def __init__(self,a):
        self.a = a

class B(A):
    def __init__(self,b,c):
        self.b = b
        self.c = c

    def printv(self):
        print(self.b)
        print(self.a)

a = B(100,300)
print(a.__dict__)       #   {'b': 100, 'c': 300}
print(a.__class__.__bases__)    #   (<class '__main__.A'>,)
a.printv()      #   100
                #   AttributeError: 'B' object has no attribute 'a'

上例代码

  • 如果B类定义时声明继承自类A,则在B类中__bases__中是可以看到类A
  • 这和是否调用类A的构造方法是两回事
  • 如果B中调用了A的构造方法,就可以拥有父类的属性了,如果理解这一句话?
class A:
    def __init__(self,a):
        self.a = a

class B(A):
    def __init__(self,b,c):
        super().__init__(b+c)
        # A.__init__(self,b+c)
        self.b = b
        self.c = c

    def printv(self):
        print(self.b)
        print(self.a)

a = B(100,300)
print(a.__dict__)       #   {'a': 400, 'b': 100, 'c': 300}
print(a.__class__.__bases__)    #   (<class '__main__.A'>,)
a.printv()      #   100
                #   400

作为好的习惯,如果父类定义了__init__方法,你就改在子类__init__中调用它【建议适用super()方法调用】

那子类什么时候自动调用父类的【__init__】方法?

例子一:【B实例的初始化会自动调用基类A的__init__方法】

class A:
    def __init__(self):
        self.a1 = "a1"
        self.__a2 = "a2"
        print("A init")

class B(A):
    pass

b = B()     #   A init
print(b.__dict__)   #   {'a1': 'a1', '_A__a2': 'a2'}

例子二:【B实例的初始化__init__方法不会自动调用父类的初始化__init__方法,需要手动调用】

class A:
    def __init__(self):
        self.a1 = "a1"
        self.__a2 = "a2"
        print("A init")

class B(A):
    def __init__(self):
        self.b1 = "b1"
        self.__b2 = "b2"
        print("b init")
        #A.__init__(self)

b = B()     #   b init
print(b.__dict__)   #   {'b1': 'b1', '_B__b2': 'b2'}

那如何正确实例化?

  • 注意,调用父类的__init__方法,出现在不同的位置,可能导致出现不同的结果
class Animal:
    def __init__(self,age):
        print("Animal init")
        self.age = age

    def show(self):
        print(self.age)

class Cat(Animal):
    def __init__(self,age,weight):
        #调用父类的__init__方法的顺序 决定show方法的结果
        super(Cat, self).__init__(age)
        print("Cat init")
        self.age = age + 1
        self.weight = weight

a = Cat(10,5)
a.show()        #   Animal init
                #   Cat init
                #   11

怎么直接将上例中所有的实例属性改变为私有属性?

  • 解决办法,一个原则,自己的私有属性,就该自己的方法读取和修改,不要借助其他类的方法,即父类或者派生类
class Animal:
    def __init__(self,age):
        print("Animal init")
        self.__age = age

    def show(self):
        print(self.__age)

class Cat(Animal):
    def __init__(self,age,weight):
        #调用父类的__init__方法的顺序 决定show方法的结果
        super(Cat, self).__init__(age)
        print("Cat init")
        self.__age = age + 1
        self.__weight = weight

    def show(self):
        print(self.__age)

a = Cat(10,5)
a.show()        #   Animal init
                #   Cat init
                #   11
print(a.__dict__)   #   {'_Animal__age': 10, '_Cat__age': 11, '_Cat__weight': 5}

到此这篇关于浅谈Python类的单继承相关知识的文章就介绍到这了,更多相关Python类的单继承内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python实现批量提取指定文件夹下同类型文件

    本文通过实例为大家分享了python实现批量提取指定文件夹下同类型文件,供大家参考,具体内容如下 代码 import os import shutil def take_samefile(or_path, tar_path, tar_type): tar_path = tar_path if not os.path.exists(tar_path): os.makedirs(tar_path) path = or_path files = os.listdir(path) # 读取or_path

  • Python绘制分类图的方法

    前言 遥感影像分类图一般为特定数值对应一类地物,用Python绘制时,主要在颜色的映射和对应的图例生成. plt.matplotlib.colors.ListedColormap支持自定义颜色.matplotlib.patches mpatches对象可以生成一个矩形对象,控制其颜色和地物类型的颜色对应就可以生成地物分类的图例了.具体用法可以自行Google和百度.下面给出一个模拟地物分类数据的可视化例子. 代码 import numpy as np import matplotlib.pypl

  • 详解python函数传参传递dict/list/set等类型的问题

    传参时传递可变对象,实际上传的是指向内存地址的指针/引用 这个标题是我的结论,也是我在做项目过程查到的.学过C的都知道,函数传参可以传值,也可以传指针.指针的好处此处不再赘述. 先上代码看看效果: def trans(var): return var source = {1: 1} dist = trans(source) source[2] = 2 print(source) print(dist) 运行结果: {1: 1, 2:2} {1: 1, 2:2} 可以看到改变了source时,di

  • python调用stitcher类自动实现多个图像拼接融合功能

    使用stitcher需要注意,图像太大会报错而且计算慢. 特点和适用范围:图像需有足够重合相同特征区域. 优点:适应部分倾斜/尺度变换和畸变情形,拼接效果好,使用简单,可以一次拼接多张图片. 缺点:需要有足够的相同特征区域进行匹配,速度较慢(和图像大小有关). 原图(可下载) 代码(两张图片拼接) import sys import cv2 if __name__ == "__main__": img1 = cv2.imread('C:/Users/Guaguan/Desktop/im

  • Python中的单继承与多继承实例分析

    本文实例讲述了Python中的单继承与多继承.分享给大家供大家参考,具体如下: 单继承 一.介绍 Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义.派生类的定义如下所示: class DerivedClassName(BaseClassName1): <statement-1> . . . <statement-N> 需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类

  • Python进阶学习之带你探寻Python类的鼻祖-元类

    Python是一门面向对象的语言,所以Python中数字.字符串.列表.集合.字典.函数.类等都是对象. 利用 type() 来查看Python中的各对象类型 In [11]: # 数字 In [12]: type(10) Out[12]: int In [13]: type(3.1415926) Out[13]: float In [14]: # 字符串 In [15]: type('a') Out[15]: str In [16]: type("abc") Out[16]: str

  • Python中的类对象示例详解

    抽象特点 Python 一切皆对象,基于此概念,对 类 class 有以下特点: 类与实例的属性 类对象创建可选择定义类属性,创建实例对象时,实例属性自动执行类的__init__方法初始化 实例对象自动继承相应的类属性(如果有),但实例属性优先级更高 实例方法,类方法,静态方法的参数 实例方法是一般函数但实例方法需要传入self参数(与一般函数的区别) 类方法和静态方法是通过装饰器实现的函数,类方法需要传入cls参数,静态方法无需传入self参数或者是cls参数(但也能传入参数) 其中self参

  • python类的继承链实例分析

    1.子类可以继承父类,同样,父类也可以继承自己的父类,一层一层地继承. class A: def have(self): print('I hava an apple') class B(A): pass class C(B): pass 2.如果想判断一个类别是否是另一个类别的子类别,可以使用内置函数issubclass(). >>> issubclass(C, A) True >>> issubclass(B, A) True >>> issubc

  • 详细总结Python类的多继承知识

    一.Python不同版本的类 Python2.2之前是没有共同的祖先的,之后引入Object类,它是所有类的共同祖先类Object Python2中为了兼容,分为古典类(旧式类)和新式类 Python3中全部都是新式类 新式类都是继承自Object的,新式类可以使用super #古典类在python2.x中运行 class A: pass print(dir(A)) # ['__doc__', '__module__'] print(A.__bases__) # () a = A() print

  • python 基于空间相似度的K-means轨迹聚类的实现

    这里分享一些轨迹聚类的基本方法,涉及轨迹距离的定义.kmeans聚类应用. 需要使用的python库如下 import pandas as pd import numpy as np import random import os import matplotlib.pyplot as plt import seaborn as sns from scipy.spatial.distance import cdist from itertools import combinations from

  • python利用K-Means算法实现对数据的聚类案例详解

    目的是为了检测出采集数据中的异常值.所以很明确,这种情况下的簇为2:正常数据和异常数据两大类 1.安装相应的库 import matplotlib.pyplot as plt # 用于可视化 from sklearn.cluster import KMeans # 用于聚类 import pandas as pd # 用于读取文件 2.实现聚类 2.1 读取数据并可视化 # 读取本地数据文件 df = pd.read_excel("../data/output3.xls", heade

  • python-pandas创建Series数据类型的操作

    1.什么是pandas 2.查看pandas版本信息 print(pd.__version__) 输出: 0.24.1 3.常见数据类型 常见的数据类型: - 一维: Series - 二维: DataFrame - 三维: Panel - - 四维: Panel4D - - N维: PanelND - 4.pandas创建Series数据类型对象 1). 通过列表创建Series对象 array = ["粉条", "粉丝", "粉带"] # 如

随机推荐