python 之面向对象(七)

news/2024/10/18 16:54:19/

1、面向对象概述

面向对象将数据与函数绑定在一起,进行封装,这样能够快速地开发程序,减少了重复代码的重写过程。
面向对象过程(Object Oriented Programming-OOP)是一种解决软件复用的设计和编程方法,这种方法把软件系统中相近相似的操作逻辑和操作应用数据状态以类的形式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

2、类和对象

1、类

类就是对一类事物的描述,是抽象的,是概念上的定义。
定义类的语法:

class 类名:方法列表

如:

class A:def f(self):print('hello')

2、对象

对象就是该类事物存在的个体(对象),也叫实例(instance)。
创建对象语法:

对象名 = 类名()

如:

# 创建对象
a = A()
# 调用方法
a.f()
# 添加属性
a.j = 12运行结果:
hello

注:所谓的 self,可以理解为自己,就是对象自身的意思。某个对象调用其方法时,python 解释器会把这个对象作为第一个参数传递给 self,所以开发者只需要传递后面的参数即可

3、init() 方法

类中有一个名为 init() 的特殊方法(即构造方法),该方法在类实例化时会自动调用,可以用作初始化操作。创建对象后,python 解释器默认调用 init() 方法
声明构造方法的语法如下:

def 类名:def __init__(self):pass

如:

# 创建类
class A:def __init__(self):print('---A init---')def print(self):print('---A---')
# 创建对象
a = A()
# 调用方法
a.print()运行结果:
---A init---   # 程序先调用构造方法
---A---

4、str() 方法

当使用 print 输出对象的时候,只要自己定义了 str(self) 方法,那么就会打印这个方法中 return 的数据

# 创建类
class A:def __init__(self):print('---A init---')def __str__(self):return 'I am str!'def print(self):print('---A---')
# 创建对象
a = A()
# 调用方法
a.print()
print(a)  # 使用print打印对象运行结果:
---A init---
---A---
I am str!

5、del() 方法

当手动或自动删除一个对象时,python 解释器都会默认调用一个方法,这个方法为 del() 方法(析构方法)

import time
class Animal(object):# 初始化方法# 创建完对象后会自动被调用def __init__(self, name):print('__init__ 方法被调用')self.__name = name# 析构方法# 当对象被删除时,会自动被调用def __del__(self):print('__del__ 方法被调用')print('%s 对象马上被干掉了' % self.__name)
# 创建对象
# dog = Animal('哈皮狗')
# print('程序两秒钟后结束')
# time.sleep(2)
# # 删除对象
# del dog
cat = Animal('波斯猫')
cat2 = cat
cat3 = cat
print('---马上删除 cat 对象---')
del cat
print('---马上删除 cat2 对象---')
del cat2
print('程序两秒钟后结束')
time.sleep(2)
print('---马上删除 cat3 对象---')
del cat3运行结果:
__init__ 方法被调用
---马上删除 cat 对象---
---马上删除 cat2 对象---
程序两秒钟后结束
---马上删除 cat3 对象---
__del__ 方法被调用
波斯猫 对象马上被干掉了

注:当程序中有其它变量引用该实例对象时(本例中除了cat,还有cat2和cat3),即便手动调用 del() 方法,该方法也不会立即执行,而是等所有的变量均被销毁后,才执行该方法,这和 Python 的垃圾回收机制的实现有关。

6、隐藏数据

如果有一个对象,当需要对其修改属性时,
对象名.属性名 = 数据 —> 直接修改
对象名.方法() —> 间接修改
为了更好地保证属性安全,即不能随意修改,一般的处理方式为:将属性定义为私有属性,添加一个可以调用的方法,供调用
如果在属性名前面加了两个下划线‘__’,则表明该属性是私有属性,否则为公有属性
方法名也是一样的,如果在方法名前面加了两个下划线则表明该方法是私有的,否则是公有的

class A:def __init__(self):self.__age = 0  # 私有属性def setAge(self, age):if 0 < age < 120:self.__age = ageelse:self.__age = 18def getAge(self):return self.__age
a = A()
a.setAge(0)
print(a.getAge())运行结果:
18

7、继承

在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系。例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物
子类在继承的时候,在定义类时,小括号()中为父类的名字
父类的属性、方法,会被继承给子类

class Animal:name = ''def eat(self):print('----吃---')def drink(self):print('---喝---')def sleep(self):print('---睡觉---')
class Dog(Animal):def bark(self):print('---叫---')
class Cat(Animal):def catch(self):print('---抓老鼠---')
hh = Cat()
hh.eat()  # 调用父类方法
hh.name = '花花'  # 调用父类属性
fg = Dog()
fg.eat()  # 调用父类方法
fg.name = '富贵'  # 调用父类属性运行结果:
-------
-------

python 中是可以多继承的,所谓多继承,即子类有多个父类,并且具有它们的特征

# 定义一个父类
class A:def printA(self):print('--A--')
# 定义一个父类
class B:def printB(self):print('--B--')
# 定义一个子类,继承自 A,B
class C(A,B):def __init__(self):super().__init__()print('---C init---')def printC(self):print('--C--')
a = C()
a.printA()
a.printB()运行结果:
---C init---
--A--
--B--

如果多个父类中有一个同名的方法,那么通过子类去调用该方法的时候,和类的对象搜索方法时的先后顺序有关

# 定义一个父类
class A:def __init__(self):print('---A init---')def print(self):print('---A---')
# 定义一个父类
class B:def __init__(self):print('---B init---')def print(self):print('---B---')
# 定义一个子类,继承自 A、B
class C(B, A):  # 先搜索Bdef __init__(self):super().__init__()print('---C init---')def printC(self):print('---C---')
c = C()
c.print()
print(C.__mro__)  # 可以查看C类的对象搜索方法的先后顺序运行结果:
---B init---
---C init---
---B---
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

8、方法重写

所谓重写,就是子类中有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

class Cat(object):def hello(self):print('hello--1')
class Bosi(Cat):def hello(self):print('hello--2')
b = Bosi()
b.hello()运行结果:
hello--2

调用父类的方法,语法格式如下:

父类类名.父类的方法(self):
super(子类的类名,self.方法名())
super().父类的方法名()
class Cat(object):def __init__(self, name):print(name)
class Basi(Cat):def __init__(self, name):# 调用父类的 __init__方法1# Cat.__init__(self, name)# 调用父类的 __init__ 方法2# super(Bosi, self).__init__(name)# 调用父类的 __init__ 方法3super().__init__(name)
b = Basi('哈米')运行结果:
哈米

9、多态

所谓多态,就是定义时的类型和运行时的类型不一样。多态的概念是应用于 Java 和 C# 这一类强类型语言中,而 Python 崇尚‘鸭子类型’,Python 伪代码可以实现 Java 和 C# 的多态

class Animal:  # 动物类def eat(self):print('动物在吃...')
class Dog(Animal):  # 狗类,继承动物类def eat(self):# Animal.eat(self)super().eat()# super(Dog, self).eat()print('狗在吃狗粮')
class Cat(Animal):  # 猫类,继承动物类def eat(self):print('猫在吃鱼')

由于在 Java 或 C# 中定义函数参数时,必须指定参数的类型,为了让 Func 函数既可以执行 Dog 对象的 eat 方法,又可以执行 Cat 对象的 eat 方法,所以需定义一个 Dog 和 Cat 的父类,而实际传入的参数是:Dog 对象和 Cat 对象

class Animal:  # 动物类def eat(self):print('动物在吃...')
class Dog(Animal):  # 狗类,继承动物类def eat(self):# Animal.eat(self)super().eat()# super(Dog, self).eat()print('狗在吃狗粮')
class Cat(Animal):  # 猫类,继承动物类def eat(self):print('猫在吃鱼')
def Func(obj):  # 调用动物吃的方法# Func 函数需要接收一个 Dog 子类的类型或者 Cat 子类的类型obj.eat()
d = Dog()
d.eat()
Func(d)  # 在 Func 函数中传入 Dog 类的对象 d,执行 Dog 的 eat 方法
c = Cat()
c.eat()
Func(c)  # 在 Func 函数中传入 Cat 类的对象 c,执行 Cat 的 eat 方法运行结果:
动物在吃...
狗在吃狗粮
动物在吃...
狗在吃狗粮
猫在吃鱼
猫在吃鱼

10、类属性、实例属性

在前面的例子中我们接触到的就是实例属性(对象属性)。顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和 C++ 中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问

类属性

class People(object):# 类属性# 可以通过对象名访问,还可以通过类名访问# 通过对象名对类属性赋值,那么范围只能在当前对象有效# 通过类名对类属性赋值,那么范围在所有对象中均有效name = 'Tom' # 公有的类属性__age = 12 # 私有的类属性
p = People()  # 实例属性(对象属性)
print(p.name) # 正确
print(People.name) # 正确
# print(p.__age) # 错误,不能在类外通过实例对象访问私有的类属性
# print(People.__age) # 错误,不能在类外通过类对象访问私有的类属性
People.name = 'Linda'
print(p.name)
print(People.name)运行结果:
Tom
Tom
Linda
Linda

如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性

class People(object):country = 'China' # 类属性
print(People.country)
p = People()
print(p.country)
p.country = 'Japan'
print(p.country)  # 实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country  # 删除实例属性
print(p.country)运行结果:
China
China
Japan
China
China

实例属性

class People:address = '青岛'phone = '0532-1234567'def __init__(self,name,id,sex,age):# 实例属性# 只能通过对象名访问self.name = nameself.id = idself.sex = sexself.age = age
p = People('张三',1,'男',18)
print(p.name)  # 正确
print(People.name)  # 错误运行结果:
张三
AttributeError: type object 'People' has no attribute 'name'

11、类方法和静态方法

1、类方法

类方法是类对象所拥有的方法,需要用修饰器 classmethod 来标识其为类方法。对于类方法,第一个对象必须是类对象,一般以 cls 作为第一个参数(也可以用其它名称作为第一个参数,但大部分人习惯以 cls 作为第一个参数的名字),能够通过实例对象和类对象去访问

class People(object):country = 'China'# 类方法,用 classmethod 来进行修斯@classmethoddef getCountry(cls):return cls.country
p = People()
print(p.getCountry)  # 通过实例对象引用
print(People.getCountry)  # 通过类对象引用运行结果:
<bound method People.getCountry of <class '__main__.People'>>
<bound method People.getCountry of <class '__main__.People'>>

2、静态方法

通过 @staticmethod 来进行修饰,静态方法不需要多定义参数

class People(object):country = 'China'@ staticmethod# 静态方法 def getCountry():return People.country
print(People.getCountry)运行结果:
<function People.getCountry at 0x00000247EFB2B130>

12、new() 方法

new 至少要有一个参数 cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供。
new 必须要有返回值,返回实例化出来的实例,这点在自己实现 __new__时要特别注意,可以 return 父类.new 出来的实例,或者直接是object 的 new 出来的实例
init 有一个参数 self,就是这个 new 返回的实例,init
new 的基础上可以完成一些其它初始化的动作,init 不需要返回值
我们可以将类比作制造商,new 方法就是前期的原材料购买环节,init 方法就是在有原材料的基础上加工,初始化商品环节。

class Dog(object):def __init__(self):print('---init 方法---')def __new__(cls):  # 此时 cls 是 Dog 指向的那个类对象print(id(cls))print('---new 方法---')return object.__new__(cls)
print(id(Dog))
p = Dog()运行结果:
2747425178016
2747425178016
---new 方法---
---init 方法---

13、单例模式

确保某一个类至少有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式

class People:__pp = Nonedef __init__(self):print('__init__')def __new__(cls):  # 通过new方法实现单例模式print('__new__')if cls.__pp == None:cls.__pp = object.__new__(cls)  # 真正意义上创建对象return cls.__ppelse:return cls.__pp
p = People()
print(p)
q = People()
print(q)
print(id(p))
print(id(q))运行结果:
__new__
__init__
<__main__.People object at 0x000001E82F0D3EB0>
__new__
__init__
<__main__.People object at 0x000001E82F0D3EB0>
2096733437616
2096733437616

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

相关文章

unity,如何让当前物体获取鼠标位置,转向鼠标在屏幕中的位置?

介绍 unity&#xff0c;如何让当前物体获取鼠标位置&#xff0c;转向鼠标在屏幕中的位置&#xff1f; 方法 void Update() {// 获取鼠标在屏幕上的位置Vector3 mousePos Input.mousePosition;// 将鼠标在屏幕上的位置转换为世界空间中的位置Vector3 worldPos Camera.main.S…

python 时间相互转换

文章目录 写在前面datetime转timestampdatetime转时间字符串timestamp转datetimetimestamp转时间字符串时间字符串转datetime时间字符串转timestamp参考文献 写在前面 对于这三者的转换&#xff0c;python2和python3是不同的&#xff0c;因为在python3中新增一些实例方法&am…

华为2023暑期笔试(1-2)

题目&#xff1a; 主办方设计了一个获取食物的游戏&#xff0c;游戏的地图由N个方格组成&#xff0c;每个方格上至多2个传送门&#xff0c;通过传送门可将参与者传送至指定的其它方格。同时&#xff0c;每个方格上标注了三个数字&#xff1a; 第一个数字id:代表方格的编号&…

【Unity-UGUI控件全面解析】| Image 图片组件详解

🎬【Unity-UGUI控件全面解析】| Image 图片组件详解一、组件介绍二、组件属性面板2.1 Image Type三、代码操作组件四、组件常用方法示例4.1 简易血条制作4.2 简易技能冷却条制作五、组件相关扩展使用5.1 Mask 遮罩💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本…

C++标准库 --- 动态内存 (Primer C++ 第五版 · 阅读笔记)

C标准库 --动态内存 (Primer C 第五版 阅读笔记&#xff09; 第12章 动态内存------(持续更新)12.1、动态内存与智能指针12.1.1、shared_ptr类12.1.2、直接管理内存12.1.3、shared_ptr和new结合使用12.1.4、智能指针和异常12.1.5、unique_ptr12.1.6、weak_ptr 12.2、动态数组1…

Elasticsearch 优化分析

Elasticsearch 优化分析 Elasticsearch 是一个分布式RESTful 风格的搜索和数据分析引擎广泛用于搜索引擎 日志分析 安全监测等领域在大数据量和高并发的场景下Elasticsearch 的性能和稳定性非常重要因此需要进行优化设计和分析 Elasticsearch 优化的重要性和目标 Elasticsea…

AI模型推理(1)——入门篇

前言 本文主要介绍AI模型推理的相关基础概念&#xff0c;为后续云原生模型推理服务的学习做准备。 初识模型部署 对于深度学习模型来说&#xff0c;模型部署指让训练好的模型在特定环境中运行的过程。相比于常规的软件部署&#xff0c;模型部署会面临更多的难题&#xff1a; …

SpringCloud微服务的熔断、限流、降级是怎么回事?

概述&#xff1a; 在开发公司商城项目时&#xff0c;由于采用的是微服务架构&#xff0c;每个模块之间使用OpenFeign组件进行通信&#xff0c;在遇到高并发时&#xff0c;为了保证系统的可用性和 可靠性&#xff0c;我们使用了阿里的Alibaba的Sentinel组件进行降级、限流和熔断…