惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
AI
AI
博客园_首页
The Last Watchdog
The Last Watchdog
S
SegmentFault 最新的问题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Know Your Adversary
Know Your Adversary
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Security Affairs
Blog — PlanetScale
Blog — PlanetScale
V2EX - 技术
V2EX - 技术
www.infosecurity-magazine.com
www.infosecurity-magazine.com
云风的 BLOG
云风的 BLOG
The GitHub Blog
The GitHub Blog
O
OpenAI News
Scott Helme
Scott Helme
C
Cisco Blogs
雷峰网
雷峰网
H
Help Net Security
P
Palo Alto Networks Blog
MyScale Blog
MyScale Blog
I
Intezer
Security Latest
Security Latest
N
News | PayPal Newsroom
美团技术团队
N
News and Events Feed by Topic
B
Blog RSS Feed
T
Tor Project blog
小众软件
小众软件
T
Tenable Blog
aimingoo的专栏
aimingoo的专栏
U
Unit 42
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
L
Lohrmann on Cybersecurity
T
Tailwind CSS Blog
K
Kaspersky official blog
C
Cyber Attacks, Cyber Crime and Cyber Security
WordPress大学
WordPress大学
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
P
Privacy International News Feed

博客园 - tsembrace

Pandas数据分析教程,由浅入深讲解(五)Pandas IO操作 Pandas数据分析教程,由浅入深讲解(四) Pandas数据分析教程,由浅入深讲解(三) Pandas数据分析教程,由浅入深讲解(二) Pandas数据分析教程,由浅入深讲解(一) B站黑马Python+AI零基础入门(二)AI应用-实战 B站黑马Python+AI零基础入门(一)AI应用-基础 B站清华128小时Python高级教程一(C1、C2) B站python入门学习---第二阶段第二章数据库、SQL和MySQL B站python入门学习---第二阶段第一章类和对象 B站python入门学习---第一阶段第十章 数据可视化 B站python入门学习---第一阶段第八~九章 文件操作、异常、模块与包 B站python入门学习---第一阶段前七章回顾复习(二) B站python入门学习---第一阶段前七章回顾复习(一) Python入门学习(十)第十四章其他 Python入门学习(九)Python的高级语法与用法(四)装饰器 Python入门学习(九)Python的高级语法与用法(三)函数式编程 Python入门学习(九)Python的高级语法与用法(二)闭包 Python入门学习(九)Python的高级语法与用法(一)枚举 Python入门学习(八)JSON、反序列化、序列化 Python入门学习(七)高级部分:正则表达式(二) Python入门学习(七)高级部分:正则表达式 Python入门学习(六)高级部分:面向对象 Python入门学习(五)函数 Python入门学习(四)流程控制 包与模块
B站清华128小时Python高级教程一(C3深入类和对象)
tsembrace · 2026-02-19 · via 博客园 - tsembrace

Chapter3  深入类和对象

一、多态和鸭子类型

1、多态:与继承(是指发生在子类和父类之间的)、重写(子类重写父类中的方法)相关。

class Animal:
    def say(self):
        print('I am an animal.')

class Cat(Animal):
    def say(self):
        print('I am a cat.')

class Dog(Animal):
    def say(self):
        print('I am a dog.')

class Duck(Animal):
    def say(self):
        print('I am a duck.')

duck = Duck()
duck.say()

dog = Dog()
dog.say()

多态中的“重写父类方法”也是面向对象语言的一种通用方式。

2、所谓的鸭子方法听视频里讲基本就是对一个对象(变量)而言,不管它实际是什么,一会儿指向A,一会儿指向B,再指向C,只需要保证任何时候这个对象(变量)都具有同一种方法即可。

如下代码中变量animal先被赋值为Cat类,后被赋值为Duck类,但它都可以实现say()方法。

class Cat:
    def say(self):
        print('I am a cat.')

class Dog:
    def say(self):
        print('I am a dog.')

class Duck:
    def say(self):
        print('I am a duck.')

animal = Cat
animal().say()

animal = Duck
animal().say()
# 关于鸭子类型的实现案例
list_a = [1, 2]
list_b = [3, 4]
list_a.extend(list_b)     #这里的可追加显而易见,因为list_a和list_b都同属列表类型
print(list_a)

set_data = set()
set_data.add(5)
set_data.add(6)

# 能否再继续在list_a上追加集合set_data呢
list_a.extend(set_data)
print(list_a)        #依然可以
# 那么为何可以呢?list_a是列表,而set_data是集合
# 原因就在于extend()方法实现上只需要是迭代类型就可以进行追加
# 这里list和set两种类型都实现了可迭代功能,这种情况也称之为“鸭子类型”

 二、抽象基类

在原先如Java中是不支持多继承的,那么针对这种需求,JAVA会提供一个特殊的类,即抽象类,无法实例化,且可以被继承,且继承抽象流之后必须重载(重写)这个抽象类的方法。

Python中也有抽象类,其作用一般为:1、进行类型判断;2、对类的方法进行限制。

如Sized就是一个python中的抽象基类,同样有:1、无法被实例化;2、继承它的类定义时须重写其方法(对Sized类这里的方法就是__len__()方法)。

其中第1条无法被实例化的原因是否也是因为这个抽象基类并没有真正实现其内部方法呢?导致实例化对象方法缺陷报错?

梳理一下:

*为什么需要抽象基类?

Python 是动态语言,默认没有“接口”或“强制契约”的概念。但在大型项目或团队协作中,我们希望:

  • 某些类不能直接使用,只能被继承;
  • 所有子类必须实现特定方法,避免遗漏;
  • 能通过 isinstance() 判断对象是否符合某种“行为协议”。

为了解决这些问题,Python 提供了 抽象基类(Abstract Base Class, ABC) 机制,通过标准库模块 abc 实现。

*抽象基类的核心作用

    1. 强制子类实现指定方法
      如果子类没有重写所有抽象方法,尝试实例化时会抛出 TypeError
    2. 支持类型判断(协议式编程)
      可用 isinstance(obj, MyABC) 判断对象是否符合某个抽象接口,即使它不是直接继承而来。

*抽象基类的定义

使用 abc 模块中的 ABC 类和 @abstractmethod 装饰器:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass  # 抽象方法,子类必须实现

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

# 错误示例:未实现抽象方法
# class Cat(Animal):
#     pass
# Cat()  # 报错:Can't instantiate abstract class Cat with abstract method make_sound

  对于上例中Cat类未实现抽象基类的方法而报错,这里的报错功能是由ABC类提供;而装饰器@abstractmethod是用来标识一个抽象基类中哪些方法是需要被重写的,ABC类需要先检查这个抽象类中有哪些必须重写的方法。(如已标识为必须重写的方法未重写,即报错)

 三、关于isinstance()和type()方法的区别

class A:
    pass

class B(A):
    pass

b = B()

# 判断b与A,B是否是同一类型
# 用isinstance判断
print(isinstance(b, B))     #输出true
print(isinstance(b, A))     #输出true

# 用type判断
print(type(b) is B)     #输出true
print(type(b) is A)     #输出false

instance()和type()的区别在于,type()只会返回和被判别对象本身的“类别”,并不会返回其父类。而instance()中只要存在继承关系,都判别为true.

对任意对象,下例都满足。

print(isinstance(b, object))

 四、类变量与实例变量(对象变量)的区别 

class A:
    #   类变量
    b = 1

    def __init__(self, x, y):
        #   实例变量
        self.x = x
        self.y = y

a = A(2, 3)

#   实例对象可以访问实例变量和类变量
print(a.x, a.y, a.b)

#   类访问类变量
print(A.b)

#   使用类去修改类变量,并用实例对象访问类对象
A.b = 18
print(A.b)
print(a.b)   #  先前创建的实例对象再去访问类变量,可以发现同样也改变了,说明这里是“引用类型”

#   使用实例对象去修改类变量
a.b = 26
print(A.b)      #   可以发现类变量并没有变化
print(a.b)      #   但是实例对象访问b却发生了改变
#   这里根本的原因是a.b = 26这一句的实质是给实例对象新创建了一个实例变量,这个实例变量只归属于这个实例对象
#   也就是说实例对象是无法修改类变量的

#   再使用类去修改类变量
A.b = 28
print(A.b)      # 28
print(a.b)      # 26,访问的还是a之前新创建的实例变量b,而非类变量b

 五、类变量与实例变量以及查找顺序 

class A:
    name = 'A'

    def __init__(self):
        self.name = 'obj'

a = A()
#   访问name变量,会在a内部先查找实例对象,如果没有,再去类中找
print(a.name)

类的多继承查找一般有两种方式:深度优先和广度优先;不同的继承关系有着不同的调用顺序

#   深度优先:从左往右查找,对A来说,即先查找B,再找D,再找C,再找E,再找Object,再没有就抛出异常
class E:
    pass

class D:
    pass

class C(E):
    pass

class B(D):
    pass

class A(B, C):
    pass

#   通过mro方法进行查找顺序的打印
print(A.__mro__)
# 输出:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
#   广度优先
class D:
    pass

class C(D):
    pass

class B(D):
    pass

class A(B, C):
    pass

# 通过mro方法进行查找顺序的打印
print(A.__mro__)