菜鸟教程《Python 3 教程》笔记(20):面向对象

菜鸟教程《Python 3 教程》笔记(20)

  • 20 面向对象
    • 20.1 面向对象技术简介
    • 20.2 创建类
      • 20.2.1 类定义
      • 20.2.2 实例化
      • 20.2.3 初始化
      • 20.2.4 类变量、实例变量
      • 20.2.5 类方法、实例方法、静态方法
    • 20.3 访问可见性
      • 20.3.1 @property装饰器
    • 20.4 动态性
      • 20.4.1 __slots__魔法
    • 20.5 继承
      • 20.5.1 多继承
      • 20.5.2 super() 函数
    • 20.6 多态
    • 20.7 类的专有方法
      • 20.7.1 运算符重载

笔记带有个人侧重点,不追求面面俱到。

20 面向对象

出处: 菜鸟教程 - Python3 面向对象

参考内容:

  1. GtiHub - jackfrued: Python-100-Days/09.面向对象进阶
  2. 知乎 - 泽霖: python类的实例方法、静态方法和类方法区别

20.1 面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法: 类中定义的函数。
  • 类变量: 类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 局部变量: 定义在方法中的变量,只作用于当前实例的类。
  • 实例变量: 在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
  • 数据成员: 类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 实例化: 创建一个类的实例,类的具体对象。
  • 对象: 通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
  • 继承: 即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 方法重写: 如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

20.2 创建类

20.2.1 类定义

使用 class 定义类。

class ClassName:<statement-1>...<statement-N>

最好使用 class ClassName(object) 的形式定义类。

类的属性和方法:

class ClassName(object):a = 0def fuc():print("Hello")

20.2.2 实例化

通过下述方法可以创建类实例。

obj = Myclass()

20.2.3 初始化

类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用。

class Complex:def __init__(self, realpart, imagpart):self.r = realpartself.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i)   # 输出结果:3.0 -4.5

self代表类的实例,而非类

类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self

class Test:def prt(self):print(self)print(self.__class__)t = Test()
t.prt()执行结果:
<__main__.Test instance at 0x100771878>
__main__.Test

从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类。

self 不是 python 关键字,把它换成 runoob 也是可以正常执行的:

class Test:def prt(runoob):print(runoob)print(runoob.__class__)t = Test()
t.prt()

20.2.4 类变量、实例变量

class test(object):a = 'cls'  # 类变量def __init__(self, num):some.b = num  # 实例变量print(test.a)
obj = test(10)
print(obj.b)
print(obj.a)

20.2.5 类方法、实例方法、静态方法

一、创建

类方法第一个参数为 cls,表示这个类本身,包含当前类的相关信息。

实例方法第一个参数为 self,表示实例本身,包含实例对象的信息。

静态方法可以不用传入参数,相当于把一个外部函数放在类中。

class test(object):a = "类变量"def __init__(self):self.b = "实例变量"@classmethoddef cls_func(cls):print("这是一个类方法")def obj_func(self):print("这是一个实例方法")@staticmethoddef func():print("这是一个静态方法")

二、调用
类内调用:

class Test(object):a = "类变量"def __init__(self):self.b = "实例变量"@classmethoddef cls_func(cls):print("这是一个类方法")def obj_func(self):print("这是一个实例方法")@staticmethoddef func():print("这是一个静态方法")# 类内调用@classmethoddef cls_func1(cls):cls.cls_func()cls.func()obj = cls()obj.obj_func()def obj_func1(self):self.cls_func()self.obj_func()self.func()@staticmethoddef func1():Test.cls_func()obj = Test()obj.obj_func()Test.func()

对象调用:

if __name__ == "__main__":test.cls_func()test.func()obj = test()obj.cls_func()obj.obj_func()obj.func()

三、使用场景

类方法一般是整个类都会使用的操作,不受实例化影响。

实例方法需要实例化,用于涉及特定实例化对象的操作。

静态方法用于不涉及类信息的操作。

四、区别

子类的实例继承了父类的static_method静态方法,调用该方法,还是调用的父类的方法和类属性。

子类的实例继承了父类的class_method类方法,调用该方法,调用的是子类的方法和子类的类属性。

20.3 访问可见性

在 Python 中,属性和方法的访问权限只有2种:公开私有。以2个下划线开头进行声明,可以将属性和方法定义为私有。声明为私有后,只能在类的内部调用 ,不能在类的外部调用。

class Test:def __init__(self, foo):self.__foo = foodef __bar(self):print(self.__foo)print('__bar')def main():test = Test('hello')# AttributeError: 'Test' object has no attribute '__bar'test.__bar()# AttributeError: 'Test' object has no attribute '__foo'print(test.__foo)if __name__ == "__main__":main()

但是,Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来妨碍对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可以验证这一点。之所以这样设定,可以用这样一句名言加以解释,就是"We are all consenting adults here"。因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。

class Test:def __init__(self, foo):self.__foo = foodef __bar(self):print(self.__foo)print('__bar')def main():test = Test('hello')test._Test__bar()print(test._Test__foo)if __name__ == "__main__":main()

在实际开发中,并不建议将属性设置为私有的,因为这会导致子类无法访问。所以大多数Python程序员会遵循一种命名惯例就是让属性名单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻。

20.3.1 @property装饰器

在不将属性直接暴露给外界的情况下,如果想访问属性可以通过属性的 getter(访问器)和 setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用 @property 包装器来包装 gettersetter 方法,使得对属性的访问既安全又方便。

class Person(object):def __init__(self, name, age):self._name = nameself._age = age# 访问器 - getter方法@propertydef name(self):return self._name# 访问器 - getter方法@propertydef age(self):return self._age# 修改器 - setter方法@age.setterdef age(self, age):self._age = agedef play(self):if self._age <= 16:print('%s正在玩飞行棋.' % self._name)else:print('%s正在玩斗地主.' % self._name)def main():person = Person('王大锤', 12)person.play()person.age = 22person.play()# person.name = '白元芳'  # AttributeError: can't set attributeif __name__ == '__main__':main()

20.4 动态性

Python 是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定

import typesclass Pearson(object):def __init__(self, name, age):self._name = nameself._age = agedef is_adult(self):if self._age >= 18:return Trueelse:return Falsedef main():boy = Pearson("小明", 16)boy._gender = "男"boy.is_adult = types.MethodType(is_adult, boy)print(boy._gender)print(boy.is_adult())del boy.is_adultdelattr(boy, "_gender")if __name__ == "__main__":main()

注意: deldelattr 功能有限,都是针对实例对象而言的,对于类方法,类属性则删除不了。

更多内容可以参考:CSDN - 涤生大数据:Python语言的动态性:运行时动态绑定,删除属性和方法

20.4.1 __slots__魔法

如果需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义 __slots__ 变量来进行限定。需要注意的是 __slots__ 的限定只对当前类的对象生效,对子类并不起任何作用

class Person(object):# 限定Person对象只能绑定_name, _age和_gender属性__slots__ = ('_name', '_age', '_gender')def __init__(self, name, age):self._name = nameself._age = age

20.5 继承

子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法:

class DerivedClassName(BaseClassName):<statement-1>...<statement-N>

基类定义在另一个模块中时,可以使用:

class DerivedClassName(modname.BaseClassName):

子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力。

20.5.1 多继承

多继承的类定义形如下:

class DerivedClassName(Base1, Base2, Base3):<statement-1>...<statement-N>

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类类中未找到时,python会从左到右查找父类中是否包含方法。

class A(object):@classmethoddef who(cls):print("A")class B(object):@classmethoddef who(cls):print("B")class C(A, B):passdef main():C.who()print(C.__mro__)  # 查看类的方法解析顺序if __name__ == "__main__":main()

更多内容可以参考:朋疏哲N:Python多继承实现以及问题应对策略

20.5.2 super() 函数

super() 函数是用于调用父类(超类)的一个方法。super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

语法:

super(type[, object-or-type])

参数:

  • type – 类。
  • object-or-type – 类,一般是 self。

实例:

class FooParent(object):def __init__(self):self.parent = 'I\'m the parent.'print ('Parent')def bar(self, message):print ("%s from Parent" % message)class FooChild(FooParent):def __init__(self):super().__init__()    print ('Child')def bar(self, message):super().bar(message)print ('Child bar fuction')print (self.parent)if __name__ == '__main__':fooChild = FooChild()fooChild.bar('HelloWorld')

菱形继承:

     ---> B ---
A --|          |--> D---> C ---

Python3 中继承遵循广度优先原则:

class A:def __init__(self):print("Enter A")print(self)print("Leave A")class B(A):def __init__(self):print("Enter B")print(self)super(B, self).__init__()print("Leave B")class C(A):def __init__(self):print("Enter C")print(self)super(C, self).__init__()print("Leave C")class D(B, C):def __init__(self):print("Enter D")print(self)super(D, self).__init__()print("Leave D")d = D()

运行结果:

Enter D
<__main__.D object at 0x7fdb02618490>
Enter B
<__main__.D object at 0x7fdb02618490>
Enter C
<__main__.D object at 0x7fdb02618490>
Enter A
<__main__.D object at 0x7fdb02618490>
Leave A
Leave C
Leave B
Leave D

20.6 多态

子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。

class Parent:        # 定义父类def myMethod(self):print ('调用父类方法')class Child(Parent): # 定义子类def myMethod(self):print ('调用子类方法')c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法
super(Child, c).myMethod()  # 用子类对象调用父类已被覆盖的方法

20.7 类的专有方法

  • __init__:构造函数,在生成对象时调用;
  • __del__:析构函数,释放对象时使用;
  • __repr__:打印,转换;
  • __setitem__:按照索引赋值;
  • __getitem__:按照索引获取值;
  • __len__:获得长度;
  • __cmp__:比较运算;
  • __call__:函数调用;
  • __add__:加运算;
  • __sub__:减运算;
  • __mul__:乘运算;
  • __truediv__:除运算;
  • __mod__:求余运算;
  • __pow__:乘方。

参考阅读:
知乎 - 黄同学:Python基础(十九):面向对象“类”之魔法方法
DataScience:Day12.魔法方法&方法重写

20.7.1 运算符重载

#!/usr/bin/python3class Vector:def __init__(self, a, b):self.a = aself.b = bdef __str__(self):return 'Vector (%d, %d)' % (self.a, self.b)def __repr__(self):return 'Vector (%d, %d)' % (self.a, self.b)def __add__(self,other):if other.__class__ is Vector:return Vector(self.a + other.a, self.b + other.b)elif other.__class__ is int:return Vector(self.a+other,self.b)def __radd__(self,other):"""反向算术运算符的重载__add__运算符重载可以保证V+int的情况下不会报错,但是反过来int+V就会报错,通过反向运算符重载可以解决此问题"""if other.__class__ is int or other.__class__ is float:return Vector(self.a+other,self.b)else:raise ValueError("值错误")def __iadd__(self,other):"""复合赋值算数运算符的重载主要用于列表,例如L1+=L2,默认情况下调用__add__,会生成一个新的列表,当数据过大的时候会影响效率,而此函数可以重载+=,使L2直接增加到L1后面"""if other.__class__ is Vector:return Vector(self.a + other.a, self.b + other.b)elif other.__class__ is int:return Vector(self.a+other,self.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
print (v1 + 5)
print (6 + v2)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/83592.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wpf资源Resources探究性学习(一)

测试环境&#xff1a; vistual studio 2017 .net framework 3.5 window 10 新建WPF应用(.net framework)&#xff0c;项目名称为&#xff1a;WpfDemo&#xff0c;如下图&#xff1a; 新建完项目后&#xff0c;默认带有一个名为MainWindow.xaml的代码 一 简单使用字符串资源…

js常用的数组处理方法

some 方法 用于检查数组中是否至少有一个元素满足指定条件。如果有满足条件的元素&#xff0c;返回值为 true&#xff0c;否则返回 false。 const numbers [1, 2, 3, 4, 5];const hasEvenNumber numbers.some((number) > number % 2 0); console.log(hasEvenNumber); /…

1_图神经网络GNN基础知识学习

文章目录 安装PyTorch Geometric安装工具包 在KarateClub数据集上使用图卷积网络 (GCN) 进行节点分类两个画图函数Graph Neural Networks数据集&#xff1a;Zacharys karate club network.PyTorch Geometric数据集介绍 edge_index使用networkx可视化展示 Graph Neural Networks…

H3C 6520X版本U盘升级

1.软件下载链接&#xff1a; 核心交换机-以太网交换机-工业交换机-新华三集团-H3C 账号&#xff1a;yx800 密码&#xff1a;01230123 2.将升级包放进U盘 3.登录交换机&#xff0c;给交换机插上U盘 >copy usba0:/S6520X-CMW710-R6628P40.ipe S6520X-CMW710-R6628P40.ip…

(并查集) 1971. 寻找图中是否存在路径 ——【Leetcode每日一题】

❓ 1971. 寻找图中是否存在路径 难度&#xff1a;简单 有一个具有 n 个顶点的 双向 图&#xff0c;其中每个顶点标记从 0 到 n - 1&#xff08;包含 0 和 n - 1&#xff09;。图中的边用一个二维整数数组 edges 表示&#xff0c;其中 edges[i] [ui, vi] 表示顶点 ui 和顶点 …

Flash的学习

Flash的学习 1 概述 2 特性 STM32 的内部FLASH 包含主存储器、系统存储器以及选项字节区域。 2.1 主存储器 主存储器分为256 页&#xff0c;每页大小为2KB&#xff0c;共512KB。这个分页的概念&#xff0c;实质就是FLASH 存储器 的扇区&#xff0c;与其它FLASH 一样&…

UWB定位模块

UWB定位模组是华星智控自研的小尺寸高集成度模组&#xff0c;模组长宽厚为30.1513.955.62毫米&#xff0c;天线采用IPEX接口分体式设计&#xff0c;方便集成于您的产品中&#xff0c;产品采用本安设计&#xff0c;可以用于煤矿等井下场景&#xff0c;通信距离>100米&#xf…

统计十进制数的二进制表示中1的个数 ← 清华 邓俊辉

【题目描述】 统计十进制数的二进制表示中1的个数。【算法分析】 虽然曾在 https://blog.csdn.net/hnjzsyjyj/article/details/110148954 发过一篇关于“统计十进制数的二进制表示中1的个数”的博客&#xff0c;但本文实现了一种新的思路。此思路来源于清华大学邓俊辉版《数据结…

什么是API接口?API接口的类型,如何调用API接口?

当今互联网技术的发展越来越快&#xff0c;越来越多的网站和应用程序需要获取外部数据来提供更好的服务和用户体验&#xff0c;这就需要使用API接口。本文将会对API接口的概念、类型以及如何调用API接口进行简要介绍。 一、什么是API接口&#xff1f; API&#xff08;Applica…

不可忽视的PG表膨胀优化

我是一个目录 案例1. 什么是表膨胀&#xff1f;2. 表膨胀危害是什么&#xff1f;3. 表膨胀是怎么产生的&#xff1f;4. 如何优化膨胀表&#xff1f; 案例 先来看一例公有云服务登录web页面端卡住案例&#xff1a; 故障现象&#xff1a;WEB端登录非常缓慢&#xff0c;需要耗时5…

前馈神经网络(FFNN)和多层感知机(MLP)

多层感知器&#xff08;MLP, Multi-Layer Perceptron&#xff09;和前馈神经网络&#xff08;Feed-Forward Neural Network, FFNN&#xff09;是深度学习中两个经常被使用的术语&#xff0c;它们经常被互换使用。让我们详细地了解这两个术语&#xff1a; 多层感知器 (MLP): M…

刷题统计(蓝桥杯)

刷题统计 问题描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 a 道题目, 周六和周日每天做 b 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 n 题? 输入格式 输入一行包含三个整数 a,b 和 n. 输出格式 输出一个整数代表…

leetcode做题笔记146. LRU 缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c;否则返回 -…

【AD】【PCB封装规范计划】 -CON排针类

像这种CON&#xff0c;排针的。画PCB封装的时候&#xff0c;要把数字用丝印标出来&#xff01;&#xff01;&#xff01;

如何使用 Node.js和Express搭建服务器?

如何使用NodeJs搭建服务器 1. 准备工作1.1 安装Node.js 2. 安装express2.1 初始化package.json2.2 安装express2.3 Express 应用程序生成器 1. 准备工作 1.1 安装Node.js Node.js 是一个开源、跨平台的 JavaScript 运行时环境。 下载链接&#xff1a;Node.js官网下载 建议下…

Java面试常用函数

1. charAt() 方法用于返回字符串指定索引处的字符。索引范围为从 0 到 length() - 1。 map.getOrDefault(num, 0) :如果map存在num这个key&#xff0c;则返回num对应的value&#xff0c;否则返回0. Arrays.sort(nums); 数组排序 Arrays.asList("a","b",&q…

Xilinx ZYNQ 7000学习笔记五(Xilinx SDK 烧写镜像文件)

概述 前面几篇讲了ZYNQ7000的启动过程&#xff0c;包括BootRom和FSBL的代码逻辑&#xff0c;其中关于FSBL代码对启动模式为JTAG被动启动没有进行分析&#xff0c;本篇将通过将JTAG的功能和通过Xilinx SDK烧写镜像文件到flash来顺道把FSBL中的JTAG代码部分给讲解下。 1.JTAG …

NuttX实时操作系统介绍(最详细)

比起安卓、iOS、鸿蒙等&#xff0c;NuttX知名度不算高&#xff0c;该系统于2007年由Gregory Nutt先生正式开源。发展至今&#xff0c;NuttX以功能丰富、性能稳定、商业化成熟度高赢得了市场的认可。 NuttX是一个成熟的实时操作系统&#xff0c;于07年由Gregory Nutt先生正式开源…

Python手写K均值算法

Python手写K均值算法 1. 算法思维导图 #mermaid-svg-AZJG7sRwopfGiqyx {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-AZJG7sRwopfGiqyx .error-icon{fill:#552222;}#mermaid-svg-AZJG7sRwopfGiqyx .error-text{fi…

学习笔记-接口测试(postman、jmeter)

目录 一、什么是接口测试 二、前端和后端 三、get请求和post请求的区别 四、cookie和session 五、接口测试的依据 六、HTTP状态码 七、通用接口用例 八、postman接口测试 九、Jmeter接口测试 一、什么是接口测试 通常做的接口测试指的是系统对外的接口&#xff0c;比…