python-面向对象:三大特性高级特性

news/2024/11/29 9:45:55/

文章目录

  • 前言
  • 一、面向对象三大特性:封装、继承、多态
    • 1.对象和类
    • 2.封装
    • 3.继承
      • (1)重写父类方法
      • (2)多继承
      • (3)私有属性与私有方法
    • 4.多态
  • 二、三大特性的应用
    • 1.链表的封装
    • 2.栈的封装
    • 3.队列的封装
    • 4.二叉树的封装
  • 三、高级特性
    • 1.类属性与实例属性
    • 2.类方法与静态方法
    • 3.property类属性
    • 4.单例模式
      • (1)基于装饰器实现单例模式
      • (2)基于new方法实现单例模式
  • 四、汇总


前言

面向过程:(Procedure Oriented)是一种以过程为中心的编程思想。分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
函数式编程:是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。
主要思想: 把运算过程尽量写成一系列嵌套的函数调用。
面向对象:是按人们认识客观世界的系统思维方式,把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。


一、面向对象三大特性:封装、继承、多态

1.对象和类

类(Class):是现实或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。
对象(Object):是具有类类型的变量。类和对象是面向对象编程技术中的最基本的概念。
类和对象的区别就是 鱼和三文鱼 的区别; 就是 猫和蓝猫 的区别。

类(Class)是是创建实例的模板
对象(Object)是一个一个具体的实例

在这里插入图片描述

在这里插入图片描述

2.封装

在这里插入图片描述

  • 构造方法__init__与其他普通方法不同的地方在于,当一个对象被创建后,会立即
    用构造方法
    。自动执行构造方法里面的内容。
  • 对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过
    对象直接或者self间接获取被封装的内容。

在这里插入图片描述
巩固封装特性:

"""
创建一个类People,
拥有的属性为姓名, 性别和年龄,
拥有的方法为购物,玩游戏,学习;实例化 对象,执行相应的方法。显示如下:
小明,18岁,男,去西安赛格购物广场购物
小王,22岁,男,去西安赛格购物广场购物
小红,10岁,女,在西部开源学习提示:
属性:name,age,gender
方法:shopping(), playGame(), learning()"""class People:def __init__(self, name, age, gender):self.name = nameself.age = ageself.gender = genderdef shopping(self):print(f'{self.name},{self.age}岁,{self.gender},去西安赛格购物广场购物 ')def learning(self):print(f'{self.name},{self.age}岁,{self.gender},在西部开源学习')p1 = People('小明', 18, '男')
p2 = People('小王', 22, '男')
p3 = People('小红', 10, '女')p1.shopping()
p2.shopping()
p3.learning()

3.继承

继承描述的是事物之间的所属关系,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类、扩展类(Subclass),而被继承的class称为基类、父类或超类(Baseclass、Superclass)。

  • 1.如何让实现继承?
    子类在继承的时候,在定义类时,小括号()中为父类的名字
  • 2.继承的工作机制是什么?
    父类的属性、方法,会被继承给子类。 举例如下: 如果子类没有定义__init__方法,父类有,那
    么在子类继承父类的时候这个方法就被继承了,所以只要创建对象,就默认执行了那个继承过来的
    __init__方法

(1)重写父类方法

重写父类方法: 就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
在这里插入图片描述
在这里插入图片描述

class Student:"""父类Student"""def __init__(self, name, age):self.name = nameself.age = agedef learning(self):print(f'{self.name}正在学习')def choice_course(self):print('正在选课中'.center(50, '*'))class MathStudent(Student):"""MathStudent的父类是Student"""def choice_course(self):# 需求: 先执行父类的choice_course方法, 在个性化执行自己的方法。# Student.choice_course(self)  # 解决方法1: 直接执行父类的方法,但不建议# 解决方法2: 通过super找到父类,再执行方法(建议且生产环境代码常用的方式)super(MathStudent, self).choice_course()info = """课程表1. 高等数学2. 线性代数3. 概率论"""print(info)# 实例化
m1 = MathStudent("粉条博士", 8)
m1.choice_course()s1 = Student("粉条博士", 8)
s1.choice_course()

(2)多继承

多继承,即子类有多个父类,并且具有它们的特征

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

"""
新式类: 广度优先算法
经典类: 深度优先算法(py2中的部分类属于经典类)python3所有的类都属于新式类。新式类的继承算法是广度优先。# 分析多继承的相关代码
>pip install djangorestframework
from rest_framework import viewsets
viewsets.ModelViewSet
"""class D(object):def hello(self):print('D')
class C(D):# def hello(self):#     print('C')pass
class B(D):pass# def hello(self):#     print('B')
class A(B, C):pass# def hello(self):#     print('A')
a = A()
a.hello()

(3)私有属性与私有方法

在 Python 中,实例的变量名如果以 __ 开头,就变成了一个私有变量/属性(private),实例的函数名如果以 __ 开头,就变成了一个私有函数/方法(private)只有内部可以访问,外部不能访问。

在这里插入图片描述

在这里插入图片描述

4.多态

多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。通俗来说: 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

多态的好处就是,当我们需要传入更多的子类,只需要继承父类就可以了,而方法既可以直接不重写(即使用父类的),也可以重写一个特有的。这就是多态的意思。调用方只管调用,不管细节,而当我们新增一种的子类时,只要确保新方法编写正确,而不用管原来的代码。这就是著名的“开闭”原则

二、三大特性的应用

1.链表的封装

"""
参考链接 https://www.cnblogs.com/klyjb/p/11237361.html
数组: 需要连续的内存空间
链表: 不需要连续的内存空间数组              链表
增加元素        O(n)                O(1)
删除元素        O(n)                O(1)
修改元素        O(1)                O(n)
查看元素        O(1)                O(n)
"""# 封装节点类
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextdef travel(self, head):"""遍历链表里面的每一个元素"""while head:print(head.val, end=',')head = head.nextdef create_l1():# l1 = 2,4,3# l2 = 5, 6, 4l1 = ListNode()node1 = ListNode(val=2)node2 = ListNode(val=4)node3 = ListNode(val=3)l1.next = node1node1.next = node2node2.next = node3return  l1.nextdef create_l2():# l1 = 2,4,3# l2 = 5, 6, 4l2 = ListNode()node1 = ListNode(val=5)node2 = ListNode(val=6)node3 = ListNode(val=4)l2.next = node1node1.next = node2node2.next = node3return  l2.nextdef addTwoNumbers(l1: ListNode, l2: ListNode) -> ListNode:res = 0l3 = ListNode()cur = l3while(l1 or l2):if(l1):res += l1.val  # res=2l1 = l1.nextif(l2):res += l2.val # res=2+5=7l2 = l2.next# res=10, val=0, res=>val val=res%10# res=14, val=4, 14%10=4l3.next = ListNode(res%10)l3 = l3.next# res=10, 进位为1, 10//10=1# res=14, 进位为1, 14//10=1res  //= 10if res == 1:l3.next = ListNode(1)return cur.next

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.栈的封装

class Stack(object):"""栈的封装[1, 2, 3, 4]"""def __init__(self):self.stack = []def push(self, value):"""入栈"""self.stack.append(value)print(f"入栈元素为{value}")def pop(self):"""出栈"""if self.is_empty():raise  Exception("栈为空")item = self.stack.pop()print(f"出栈元素为{item}")return  itemdef is_empty(self):"""判断栈是否为空"""return  len(self.stack) == 0def top(self):"""返回栈顶元素"""if self.is_empty():raise  Exception("栈为空")return  self.stack[-1]def __len__(self):"""魔术方法, len(object)自动执行的方法"""return  len(self.stack)if __name__ == '__main__':stack = Stack()stack.push(1)stack.push(2)stack.push(3)print(len(stack))  # 3stack.pop()print(stack.is_empty()) # Falseprint(stack.top())  # 2

3.队列的封装

class Queue(object):"""队列的封装1. 列表的左侧队尾2. 列表的右侧队头"""def __init__(self):self.queue = []def enqueue(self, value):"""入队"""self.queue.insert(0, value)print("入队元素为:", value)def dequeue(self):"""出队"""if self.is_empty():raise  Exception("队列为空")item = self.queue.pop()print("出队元素:", item)return  itemdef __len__(self):"""获取队列的长度"""return  len(self.queue)def first(self):"""获取队头元素"""if self.is_empty():raise Exception("队列为空")return  self.queue[-1]def last(self):"""获取队尾元素"""if self.is_empty():raise Exception("队列为空")return  self.queue[0]def is_empty(self):"""判断队列是否为空"""return  len(self.queue) == 0if __name__ == '__main__':queue = Queue()queue.enqueue(1)queue.enqueue(2)queue.enqueue(3)print(queue.is_empty()) # Falsequeue.dequeue()  # 1出队, 队列只剩32print(queue.first())  # 2print(queue.last())  # 3

4.二叉树的封装

"""
二叉树:https://www.cnblogs.com/polly333/p/4740355.html
"""class Node(object):"""节点类"""def __init__(self, val=None, left=None, right=None):self.val = valself.left = leftself.right = rightclass BinaryTree(object):"""封装二叉树"""def __init__(self, root):self.root = rootdef pre_travel(self, root):"""先序遍历: 根左右"""if (root != None):print(root.val)self.pre_travel(root.left)self.pre_travel(root.right)def in_travel(self, root):"""中序遍历: 左根右"""if (root != None):self.in_travel(root.left)print(root.val)self.in_travel(root.right)def last_travel(self, root):"""后序遍历: 左右根"""if (root != None):self.last_travel(root.left)self.last_travel(root.right)print(root.val)if __name__ == '__main__':node1 = Node(1)node2 = Node(2)node3 = Node(3)node4 = Node(4)node5 = Node(5)node6 = Node(6)node7 = Node(7)node8 = Node(8)node9 = Node(9)node10 = Node(10)bt = BinaryTree(root=node1)node1.left = node2node1.right = node3node2.left = node4node2.right= node5node3.left = node6node3.right = node7node4.left = node8node4.right = node9node5.left = node10# 先序遍历bt.pre_travel(node1)

三、高级特性

1.类属性与实例属性

类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本
在前面的例子中我们接触到的就是实例属性(对象属性),它不被所有类对象的实例对象所共有,在内存中的副本个数取决于对象个数。

2.类方法与静态方法

类方法是类对象所拥有的方法,需要用修饰器一般以==@classmethod==来标识其为类方法,
1). 对于类方法,第一个参数必须是类对象,作为第一个参数
(cls是形参, 可以修改为其它变量名,但最好用’cls’了)
2). 能够通过实例对象和类对象去访问。

静态方法需要用修饰器一般以==@staticmethod==来标识其为静态方法,
1). 静态方法不需要多定义参数
2). 能够通过实例对象和类对象去访问。

在这里插入图片描述

在这里插入图片描述

3.property类属性

一种用起来像是使用的实例属性一样的特殊属性,可以对应于类的某个方法。
property属性的定义和调用要注意一下几点:
1.定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
2.调用时,无需括号
在这里插入图片描述

"""
类属性应用需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:
- 根据用户请求的当前页和总数据条数计算出 m 和 n
- 根据m 和 n 去数据库中请求数据from datetime import  datetime
"""class Page(object):"""[user1, user2, user3......user100]page=2, per_page=10第一页: start=0 end=10第二页: start=10 end=20第三页: start=20 end=30....第page页: start=(page-1)*per_page end=page*per_page"""def __init__(self, page, per_page=10):self.page = pageself.per_page = per_page# 类属性: 将类方法变成类属性的过程。@propertydef start(self):return (self.page-1) * self.per_page@propertydef end(self):return  self.page * self.per_pageif __name__ == '__main__':goods = ['good'+str(i+1) for i in range(100)]page = Page(page=10, per_page=3)print(goods[page.start:page.end])

property简单案例:

在这里插入图片描述

4.单例模式

在这里插入图片描述

(1)基于装饰器实现单例模式

在这里插入图片描述

(2)基于new方法实现单例模式

在这里插入图片描述

四、汇总

面向对象:

    1. 三大特性封装(必须要掌握的):__new__: 在实例化对象之前执行的, 返回对象。__init__: 构造方法, 实例化对象时自动执行。 常用于将对象和属性绑定在一起。self: 实质上是对象。继承(最多知识点的):多继承算法: python3中广度优先算法。私有属性和私有方法多态(最简单的):2. 三大特性的应用1). 链表的封装(Leetcode第二题)2). 栈的封装3). 队列的封装4). 二叉树的封装与先序遍历3. 高级特性1). @classmethod和@staticmethod(类方法和静态方法)2). @property类属性3). 单例模式: 一个类只能实例化一个对象基于装饰器基于new方法


http://www.ppmy.cn/news/288779.html

相关文章

新同居时代

新同居时代【转载】 ID:愤怒的螃蟹 一  偷眼看了看不远处的经理。见他仍全神贯注地继续玩着他那弱智的联众。悄悄的溜回自己的电脑前打开qq。 “嘿,干什么呢?”哥们见我上线和我打招呼。 “上班呢”给他回一句后再偷偷的看经理一眼。 “还在那公司做…

三星s6开机无显示无服务器,三星Galaxy S6手机不能开机怎么办?三星Galaxy S6手机不能开机解决办法...

三星Galaxy S6手机不能开机怎么办呢?可能很多使用三星Galaxy S6的用户会有这样的问题,三星Galaxy S6在入手之后,可能由于一些不恰当的操作或者刷机,导致手机无法开机,那么如果遇到这样的问题,我们可以怎么来…

三星Galaxy Tab S6与Tab S7的任何区别

Samsung’s Galaxy Tab S7 was recently announced at Samsung’s Unpacked event which featured products like the Note20 Ultra, Galaxy Buds Live, and more products! Last year, Samsung released the Galaxy Tab S6, which was a great 2-in-1 device which consumers …

三星S6的Wifi连接上了,却无法上网

三星S6手机的Wifi连接上了,应用却无法上网! 如何解? 答: 进入设置——》流量监控——》管理应用程序流量, 数据和WLAN全勾上就OK啦! 注意是“全勾上”哟。

gdb调试中出现optimized out

转自&#xff1a;上善若水 问题 print变量中出现<optimized out>。 解决 添加编译选项-O0&#xff0c;意思是不进行编译优化&#xff0c;gdb在默认情况下会使用-O2。 使用-O0选项调试的时候就会顺畅了,发布项目的时候不用再使用 -O0参数项&#xff0c;gcc 默认编译或…

gdb调试 出现value optimized out解决方法

现象&#xff1a; gdb调试 出现value optimized out解决方法原因&#xff1a; 由于gcc在编译过程中默认使用-O2优化选项&#xff0c;希望进行单步跟踪调试时&#xff0c;应使用-O0选项。 解决办法&#xff1a; 使用-O0选项 附录&#xff08;优化等级的说明&#xff09;&am…

gdb optimized out

转载地址:https://blog.csdn.net/zhangxiao93/article/details/51934354 gdb optimized out 问题 print变量中出现<optimized out>。 解决 添加编译选项-O0&#xff0c;意思是不进行编译优化&#xff0c;gdb在默认情况下会使用-O2。 使用-O0选项调试的时候就会顺畅了…

内核调试出现value optimized out的问题

最近在用gdb调试内核的过程中经常会有< value optimized out>的提示&#xff0c; 首先分析该提示出现的原因&#xff0c;我的理解是可能这些被优化的变量已从内存中被移到了寄存器中&#xff0c;所以会找不到。 为了能在调试过程中看到所有的变量&#xff0c;不知道能不…