Python系列之面向对象编程

news2024/11/17 5:32:32

目录

一、面向对象编程

1.1 面向对象三大特征

1.2 什么是对象

二、类(class)和实例(instance)

2.1 类的构成

2.2 创建类

2.3 创建实例对象和访问属性

2.4 Python内置类属性

2.5 类属性与方法

三、类的继承

3.1 方法重写

四、多态


一、面向对象编程


1.1 面向对象三大特征


面向对象编程的三大特征:封装,集成,多态

封装:客观的事物封装成类(将数据和方法放在一个类中就构成了封装)

继承:在Python中一个类可以集成于另一个类也可以继承多个类,被继承的类叫父类(或者叫基类,base class),继承的类叫子类

多态(polymorphism):指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度

  • 面向对象编程(Object Oriented Programming),简称OOP,是一种程序设计思想,OOP把对象当作程序的基本单元一个对象包含了数据和操作数据的函数
  • 面向对象的程序设计把计算机程序当作一组对象的集合,每个对象都可以接受其他对象发来的消息,并且进行处理,而计算机程序的执行就是一系列消息在各对象之间进行传递,和面向对象不同,面向过程的程序设计把计算机程序当作一系列的命令集合,即一组函数的顺序执行,为了简化程序设计,面向过程把函数继续切分为子函数,从而降低系统的复杂度。
  • 在Python中,所有的数据类型都可以看作为对象,当然也可以自定义对象,自定义的对象数据类型就是面向对象中类(class)的概念,下面来看一个案例来说明面向对象和面向过程的区别:

实例:

stu01 = {'name': "张三丰", 'age': "110", 'address': "上海"}
stu02 = {'name': "张无忌", 'age': "200", 'address': "西安"}
stu03 = {'name': "张无忌", 'age': "200", 'address': "北京"}


def print_info(stu):
    return print('%s : %s : %s' % (stu['name'], stu['age'], stu['address']))


print_info(stu01)
print_info(stu02)
print_info(stu03)
print("++++++++++++++++")


# 面向对象
class Person(object):
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def getInfo(self):
        print(self.name, self.age, self.address)


p01 = Person("张三丰", 110, "北京")
p02 = Person("张启山", 110, "西安")
p01.getInfo()
p02.getInfo()

执行结果:

1.2 什么是对象


对象(class)是一种抽象的概念,上面定义的对象Person,指的就是学生这个概念,而实例(instance)则指一个个具体的对象,例如上面的张三丰和l张无忌就是两个具体的Person,也就是实例

从上面的案例可以看出,面向对象的程序设计思想其实就是抽象出对象(class),然后根据对象创建实例(instance)

最后,面向对象的抽象程度比函数高,因为一个对象既包含数据,也包含操作数据的方法,封装、继承、多态是面向对象的三大特点。


二、类(class)和实例(instance)


类是总结事物特征的抽象概念,是创建对象的模板。对象是按照类来具体化的实物。是总结事物特征的抽象概念,是创建对象的模板。对象是按照类来具体化的实物。

2.1 类的构成


  • 类的名称: 类名
  • 类的属性: 一组参数数据
  • 类的方法: 操作的方式或行为

面向对象最重要的概念就是类(class)和实例(instance),类是抽象的模板,比如上面的Person类,而实例是根据类创建出来的具体的对象,每个对象都有相同的方法,但是各自的数据可能不同,例如上面的张三丰和l张无忌。

2.2 创建类


使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class ClassName:
   '类的帮助信息'   #类文档字符串
   class_suite  #类体

以Person类为例

# 面向对象
class Person(object):
    personCnt = 0
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def getInfo(self):
        print(self.name, self.age, self.address)

    def displayCount(self):
        print("类的属性:", self.personCnt)



在Python中,类是通过'class'关键字进行定义的,'class'后面跟着的是类名,
类名通常是以大写字母开头的,紧接着就是'(object)',
这个表示的是'Person'类是从'object'类继承下来的。
  • 方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法当创建了这个类的实例时就会调用该方法
    
    self 代表类的实例,self 在定义类的方法时是必须有的虽然在调用时不必传入相应的参数。
  • personCnt变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Person.personCnt 访问。

self代表类的实例,而非类

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

class ObjTest:
    def print_info(self):
        print("当前对象地址: ", self)
        print("指向类: " , self.__class__)


objTest = ObjTest()
objTest.print_info()

objTest1 = ObjTest()
objTest1.print_info()

执行结果:

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

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

class ObjTest:
    def print_info(runoob):
        print("当前对象地址: ", runoob)
        print("指向类 : " , runoob.__class__)


objTest = ObjTest()
objTest.print_info()

objTest1 = ObjTest()
objTest1.print_info()

执行结果:

2.3 创建实例对象和访问属性


实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。

以下使用类的名称 Person 来实例化,并通过 __init__ 方法接收参数。

# 面向过程
stu01 = {'name': "张三丰", 'age': "110", 'address': "上海"}
stu02 = {'name': "张无忌", 'age': "200", 'address': "西安"}
stu03 = {'name': "张无忌", 'age': "200", 'address': "北京"}


def print_info(stu):
    return print('%s : %s : %s' % (stu['name'], stu['age'], stu['address']))


print_info(stu01)
print_info(stu02)
print_info(stu03)
print("++++++++++++++++")


# 面向对象
class Person(object):
    personCnt = 0

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        # 使用点号 . 来访问对象的属性
        Person.personCnt += 1

    def getInfo(self):
        print(self.name, self.age, self.address)

    def displayCount(self):
        print("类的属性:", self.personCnt)


# 创建 Person 类的第一个对象
p01 = Person("张三丰", 110, "北京")
# 创建 Person 类的第二个对象
p02 = Person("张启山", 110, "西安")
p01.getInfo()
p02.getInfo()
p01.displayCount()
p01.personCnt = 5
print("类的属性personCnt修改: ", p01.personCnt)
del p01.personCnt
print("删除类的属性personCnt: ", p01.personCnt)

执行结果:

可以使用以下函数的方式来访问属性:

  • getattr(obj, name[, default]) : 访问对象的属性。
  • hasattr(obj,name) : 检查是否存在一个属性。
  • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
  • delattr(obj, name) : 删除属性。

实例:

stu01 = {'name': "张三丰", 'age': "110", 'address': "上海"}
stu02 = {'name': "张无忌", 'age': "200", 'address': "西安"}
stu03 = {'name': "张无忌", 'age': "200", 'address': "北京"}


def print_info(stu):
    return print('%s : %s : %s' % (stu['name'], stu['age'], stu['address']))


print_info(stu01)
print_info(stu02)
print_info(stu03)
print("++++++++++++++++")


# 面向对象
class Person(object):
    personCnt = 0

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        # 使用点号 . 来访问对象的属性
        Person.personCnt += 1

    def getInfo(self):
        print(self.name, self.age, self.address)

    def displayCount(self):
        print("类的属性:", self.personCnt)


# 创建 Person 类的第一个对象
p01 = Person("张三丰", 110, "北京")

getPersonCnt = getattr(p01, "personCnt")
print("getattr 类的属性personCnt : ", getPersonCnt)

hasPersonCnt = hasattr(p01, "personCnt")
hasPersonCnt01 = hasattr(p01, "personCnt01")

print("hasattr 类的属性personCnt : ", hasPersonCnt)
print("hasattr 类的属性personCnt01 : ", hasPersonCnt01)

setattr(p01, "personCnt", 8)
print("setattr 类的属性personCnt : ", p01.personCnt)

执行结果:

2.4 Python内置类属性


  • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
  • __doc__ :类的文档字符串
  • __name__: 类名
  • __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
  • __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

实例:

# 面向对象
class Person(object):
    """所有人员的基类"""
    personCnt = 0

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
        # 使用点号 . 来访问对象的属性
        Person.personCnt += 1

    def getInfo(self):
        print(self.name, self.age, self.address)

    def displayCount(self):
        print("类的属性:", self.personCnt)


# 创建 Person 类的第一个对象
p01 = Person("张三丰", 110, "北京")
# 创建 Person 类的第二个对象
p02 = Person("张无忌", 110, "西安")

print("类的文档字符串 Person.__doc__:", Person.__doc__)
print("类名 Person.__name__:", Person.__name__)
print("类定义所在的模块 Person.__module__:", Person.__module__)
print("类的所有父类构成元素 Person.__bases__:", Person.__bases__)
print("类的属性字典 Person.__dict__:", Person.__dict__)

执行结果:

2.5 类属性与方法


  • 类的私有属性

__private_attrs两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs

  • 类的方法

在类的内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数

  • 类的私有方法

__private_method:两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 self.__private_methods

实例:

# 面向对象
class Person(object):
    """所有人员的基类"""
    # 公开变量
    personCnt = 0
    # 私有变量
    __secretPersonCnt = 0

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def getInfo(self):
        print("公共属性: ", self.name, self.age, self.address)

    def displayCount(self):
        self.__secretPersonCnt += 1
        # 使用点号 . 来访问对象的属性
        self.personCnt += 1
        print("类的公共属性:", self.personCnt, "类的私有属性:", self.__secretPersonCnt)


# 创建 Person 类的第一个对象
p01 = Person("张三丰", 110, "北京")
# 创建 Person 类的第二个对象
p02 = Person("张无忌", 110, "西安")
p01.getInfo()
p01.displayCount()

print("类的公共属性:", p01.personCnt)
print("类的私有属性:", p01.__secretPersonCnt)

执行结果:

如果 我们使用Pycharm 编辑代码,用实例 “.” 类的私有属性是不能联想出来的。

可以使用 object._className__attrName对象名._类名__私有属性名 )访问属性

# 面向对象
class Person:
    # 私有变量
    __secretPersonCnt = "背着那书包上学堂,不怕太阳晒不怕风雨吹 "


person = Person
print("类的私有属性访问:", person._Person__secretPersonCnt)

执行结果:


三、类的继承


面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

通过继承创建的新类称为子类派生类,被继承的类称为基类父类超类

继承语法

class 派生类名(基类名)
    ...

在python中继承中的一些特点:

  • 1、如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法。详细说明可查看:python 子类继承父类构造函数说明。
  • 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
  • 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。

派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:

class Parent:
    parentAttr = 100

    def __init__(self):
        print("调用父类构造函数")

    def parentMethod(self):
        print("调用父类方法")

    def setAttr(self, attr):
        Parent.parentAttr = attr

    def getAttr(self):
        print("父类属性:", Parent.parentAttr)


class Child(Parent):
    def __init__(self):
        print("调用子类的构造函数")

    def childMethod(self):
        print("调用子类方法")


c = Child()  # 实例化子类
c.childMethod()  # 调用子类方法
c.parentMethod()  # 调用父类方法
c.setAttr(200)  # 再次调用父类的方法 - 设置属性值
c.getAttr()  # 再次调用父类的方法 - 获取属性值

执行结果:

说明:

  • 上面的案例Child 就是 Parent的子类,Parent 是 Child 的父类;
  • Child 继承 Parent后,可以直接使用 Parent 中的方法,这也是继承最大的好处:子类可以获得父类的全部功能

3.1 方法重写


如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:

class Parent:

    def __init__(self):
        print("调用父类构造函数")

    def myMethod(self):
        print("调用父类方法")


class Child(Parent):
    parentAttr = 100

    def __init__(self):
        print("调用子类的构造函数")

    def myMethod(self):
        print("调用子类方法", Child.parentAttr + 1)


c = Child()  # 实例化子类
c.myMethod()  # 子类调用重写方法

执行结果:

子类对 myMethod 方法 重写,输出的是 子类的 打印信息,重写是:当子类和父类同时存在相同的方法时,在调用子类的时候,子类的方法会覆盖掉父类的方法。


四、多态


多态(polymorphism):指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度。类的多态特性,还要满足以下 2 个前提条件

  1. 继承多态一定是发生在子类和父类之间;
  2. 重写:子类重写父类的方法。
class Animal(object):
    """动物类"""

    def func(self):
        print('动物发出了声音')


class Cat(Animal):
    """猫类"""

    def func(self):
        print('猫:喵 喵 喵')


class Dog(Animal):
    """狗类"""

    def func(self):
        print('狗:汪 汪 汪 ')


def work(a: Animal):
    a.func()


dog = Dog()
cat = Cat()
work01(dog)
work01(cat)

执行结果:

可以看到,Dog 和 Cat 都继承自 Animal 类,且各自都重写了父类的 func() 方法。从运行结果可以看出,在work()方法中, 传入 cat 和 dog 实例 执行同一个 func() 方法时,由于 a 实际表示不同的类实例对象,因此 a.func() 调用的并不是同一个类中的 func() 方法,这就是多态。

————————————————
此文参考廖雪峰官网:面向对象编程 - 廖雪峰的官方网站 (liaoxuefeng.com)

原文链接:Python(8)面向对象编程_用面向对象为电脑估价python_礁之的博客-CSDN博客

Python 面向对象 | 菜鸟教程

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

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

相关文章

抖音短视频矩阵系统-源码-系统搭建

目录 1. 短视频AI智能创作 2. 托管式账号管理: 3. 数据分析 4. 智能营销获客 开发流程 抖音账号矩阵系统开发,抖音账号矩阵系统源码搭建,抖音账号技术系统源码部署 抖音矩阵系统专注于为短视频私域运营达人或企业提供一站式赋能服务平台。具体包括智…

小议CSDN周赛57期 - 凑数

本期周赛几乎忘记参加,在最后几分钟的时候上来看了看。那些选择判断一通乱选,填空题也已经被吐槽得差不多了,这里不多说,只说我对第一道编程题的看法(吐槽)。因为 C 站的机制是,即使它错了&…

彻底理解HTTPS加密原理

目录 1.为什么需要加密? 2.什么是对称加密? 3.什么是非对称加密? 4.非对称加密对称加密? 5.数字证书 6.数字签名 相信大家对于HTTP与HTTPS的区别都有了解,那么对于HTTPS的加密过程你是否知道呢? 对称…

单片机内存管理

单片机内存管理 1、随机存储器 RAM是随机存储器,读写速度快,但掉电以后数据会丢失。它分为SRAM(静态RAM)和DRAM(动态RAM)。SRAM无需刷新就可以保存数据;DRAM需要不断刷新才可以保存数据。在CPU内部的RAM,就叫内部RAM&#xff0c…

算法模板(3):搜索(4):高等图论

高等图论 有向图的强连通分量 相关概念 强连通分量:Strongly Connected Component (SCC).对于一个有向图顶点的子集 S S S,如果在 S S S 内任取两个顶点 u u u 和 v v v,都能找到一条 u u u 到 v v v 的路径,那么称 S S…

JVM零基础到高级实战之Java程序员不可不知的对象创建底层步骤细节

JVM零基础到高级实战之Java程序员不可不知的对象创建底层步骤细节 JVM零基础到高级实战之Java程序员不可不知的对象创建底层步骤细节 文章目录 JVM零基础到高级实战之Java程序员不可不知的对象创建底层步骤细节前言Java对象创建的流程步骤包括哪些?总结 前言 JVM零…

【云原生 | 53】Docker三剑客之Docker Compose应用案例一:Web负载均衡

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专…

基于Echarts构建停车场数据可视化大屏(文末送书)

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

【部署LVS-DR 群集】

目录 一、DR模式 LVS负载均衡群集1、数据包流向分析2、DR 模式的特点 二、DR模式 LVS负载均衡群集部署1、1.配置负载调度器(192.168.80.30)(1)配置虚拟 IP 地址(VIP:192.168.102.188)&#xff0…

《设计模式》之装饰器模式

文章目录 1、定义2、动机3、类结构4、优缺点5、注意事项6、总结7、代码实现(C) 1、定义 动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码…

PPT中这8个隐藏技巧-掌握了马上让你幸福感满满

开篇 一个好的PPT需要精雕细琢。即使我们使用了AIGC特别是时下流行的用GPT书写大纲,然后把大纲内的内容放到一些自动GC PPT内容的生成器里生成后的PPT其实也不是马上可以拿来用的。工作上一份大领导、公司、集团级别的PPT不可能90%使用GPT GC生成就可以直接交付的。比如说我们…

Trie树模板与应用

文章和代码已经归档至【Github仓库:https://github.com/timerring/algorithms-notes 】或者公众号【AIShareLab】回复 算法笔记 也可获取。 文章目录 Trie树(字典树)基本思想例题 Trie字符串统计code关于idx的理解 模板总结应用 最大异或对分…

初探BERTPre-trainSelf-supervise

初探Bert 因为一次偶然的原因,自己有再次对Bert有了一个更深层地了解,特别是对预训练这个概念,首先说明,自己是看了李宏毅老师的讲解,这里只是尝试进行简单的总结复述并加一些自己的看法。 说Bert之前不得不说现在的…

ansible远程执行指令,/bin/sh: java: command not foundnon-zero return code

问题描述:ansible远程执行指令,初选指令加载不全, [rootVM-0-6-centos ~]# ansible all -m shell -a "java -version" 10.206.0.15 | FAILED | rc127 >> /bin/sh: java: command not foundnon-zero return code 解决方案&a…

C++(8):IO 库

IO 类 IO 库类型和头文件 iostream 定义了用于读写流的基本类型,fstream 定义了读写命名文件的类型,sstream 定义了读写内存 string 对象的类型。 其中带 w 前缀的类型用来操作宽字符语言 (wchar_t)。宽字符版本的类型和函数前都有一个 w,如…

SAP从入门到放弃系列之PP/DS-part1

翻译一篇大佬文章,了解一下PPDS前世今生和产品功能出现的业务背景。虽然是15年的,但经典永流传~~~,感谢大佬的文章。 原文地址: #S4HANA 1610 use case series: 9a – Production Planning and Detailed Scheduling – PP/DS (b…

【MySQL学习笔记】子查询与联结(连接)

1.子查询 将一条select语句返回的结果用于另一条select语句的where子句中。 执行时,先执行子查询,再执行主查询。 select sid from sc where cid in (select cid from course where cname数据库应用技术);子查询一般与 IN 操作符结合使用&#xff0…

《微服务实战》 第三十二章 微服务链路跟踪-sleuth zipkin

前言 大型分布式微服务系统中,一个系统被拆分成N多个模块,这些模块负责不同的功能,组合成一套系统,最终可以提供丰富的功能。在这种分布式架构中,一次请求往往需要涉及到多个服务服务之间的调用错综复杂,对…

Lenovo Yoga-710-14IKB电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网,转载需注明出处。(下载请直接百度黑果魏叔) 硬件配置 硬件型号驱动情况 主板Lenovo Yoga 710 (14") - 14IKB (without dGPU) 处理器Intel i5-7200U (4) 2.50GHz (IKBL)已驱动 内存48 GB ( 海盗船 DDR4 3200…

web worker创建多个 JavaScript 线程 (使用GTP写的文章)

前言 最近在优化公司的一个项目,使用的就是web worker去优化,做了那些优化,一个是状态的优化,(通信的状态实时更新,以前的做法是做个定时任务实时获取它的状态,然后让它在页面渲染,这…