首页 > 编程语言 >31:Python面向对象的程序设计

31:Python面向对象的程序设计

时间:2024-09-08 16:05:14浏览次数:7  
标签:__ name People Python 31 面向对象 对象 self def

一、面向对象的程序设计

什么是面向对象的程序设计及为什么要有它

面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。

优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)

缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。

应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。



二 、面向对象的程序设计:核心是对象二字,(要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取),对象是特征与技能的结合体,基于面向对象设计程序就好比在创造一个世界,你就是这个世界的上帝,存在的皆为对象,不存在的也可以创造出来,与面向过程机械式的思维方式形成鲜明对比,面向对象更加注重对现实世界的模拟,是一种“上帝式”的思维方式。

优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。

缺点:

1. 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。

2. 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。

应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方

面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。

三 、类与对象
类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体

那么问题来了,先有的一个个具体存在的对象(比如一个具体存在的人),还是先有的人类这个概念,这个问题需要分两种情况去看

在现实世界中:先有对象,再有类

世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念

也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在

在程序中:务必保证先定义类,后产生对象

这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类

不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象

按照上述步骤,我们来定义一个类(我们站在学校的角度去看,在座的各位都是学生)

#在现实世界中,站在Python学校的角度:先有对象,再有类
对象1:李坦克
特征:
学校=goodboy
姓名=李坦克
性别=男
年龄=18
技能:
学习
吃饭
睡觉

对象2:王大炮
特征:
学校=goodboy
姓名=王大炮
性别=女
年龄=38
技能:
学习
吃饭
睡觉

对象3:牛榴弹
特征:
学校=goodboy
姓名=牛榴弹
性别=男
年龄=78
技能:
学习
吃饭
睡觉


现实中的老男孩学生类
相似的特征:
学校=goodboy
相似的技能:
学习
吃饭
睡觉

在现实世界中:先有对象,再有类

# 在程序中,务必保证:先定义(类),后使用(产生对象)
PS:
1.
在程序中特征用变量标识,技能用函数标识
2.
因而类中最常见的无非是:变量和函数的定义

# 程序中的类


class GoodboyStudent:
school = 'Goodboy'

def learn(self):
print('is learning')

def eat(self):
print('is eating')

def sleep(self):
print('is sleeping')

# 注意:


1.
类中可以有任意python代码,这些代码在类定义阶段便会执行
2.
因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过GoodboyStudent.__dict__查看
3.
对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法
4.
点是访问属性的语法,类中定义的名字,都是类的属性

# 程序中类的用法
.:专门用来访问属性,本质操作的就是__dict__
GoodboyStudent.school # 等于经典类的操作GoodboyStudent.__dict__['school']
GoodboyStudent.school = 'Goodboy' # 等于经典类的操作GoodboyStudent.__dict__['school']='Goodboy'
GoodboyStudent.x = 1 # 等于经典类的操作GoodboyStudent.__dict__['x']=1
del GoodboyStudent.x # 等于经典类的操作GoodboyStudent.__dict__.pop('x')

# 程序中的对象
# 调用类,或称为实例化,得到对象
s1 = GoodboyStudent()
s2 = GoodboyStudent()
s3 = GoodboyStudent()


# 如此,s1、s2、s3都一样了,而这三者除了相似的属性之外还各种不同的属性,这就用到了__init__
# 注意:该方法是在对象产生之后才会执行,只用来为对象进行初始化操作,可以有任意代码,但一定不能有返回值
class GoodboyStudent:
......

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

......


s1 = GoodboyStudent('李坦克', '男', 18) # 先调用类产生空对象s1,然后调用GoodboyStudent.__init__(s1,'李坦克','男',18)
s2 = GoodboyStudent('王大炮', '女', 38)
s3 = GoodboyStudent('牛榴弹', '男', 78)

# 程序中对象的用法
# 执行__init__,s1.name='牛榴弹',很明显也会产生对象的名称空间
s2.__dict__
{'name': '王大炮', 'age': '女', 'sex': 38}

s2.name # s2.__dict__['name']
s2.name = '王三炮' # s2.__dict__['name']='王三炮'
s2.course = 'python' # s2.__dict__['course']='python'
del s2.course # s2.__dict__.pop('course')
在程序中:先定义类,后产生对象

-------细说__init__方法----------------
#方式一、为对象初始化自己独有的特征
class People:
country='China'
x=1
def run(self):
print('----->', self)

# 实例化出三个空对象
obj1=People()
obj2=People()
obj3=People()

# 为对象定制自己独有的特征
obj1.name='egon'
obj1.age=18
obj1.sex='male'

obj2.name='lxx'
obj2.age=38
obj2.sex='female'

obj3.name='alex'
obj3.age=38
obj3.sex='female'

# print(obj1.__dict__)
# print(obj2.__dict__)
# print(obj3.__dict__)
# print(People.__dict__)





#方式二、为对象初始化自己独有的特征
class People:
country='China'
x=1
def run(self):
print('----->', self)

# 实例化出三个空对象
obj1=People()
obj2=People()
obj3=People()

# 为对象定制自己独有的特征
def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
obj.name = x
obj.age = y
obj.sex = z

chu_shi_hua(obj1,'egon',18,'male')
chu_shi_hua(obj2,'lxx',38,'female')
chu_shi_hua(obj3,'alex',38,'female')





#方式三、为对象初始化自己独有的特征
class People:
country='China'
x=1

def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
obj.name = x
obj.age = y
obj.sex = z

def run(self):
print('----->', self)


obj1=People()
# print(People.chu_shi_hua)
People.chu_shi_hua(obj1,'egon',18,'male')

obj2=People()
People.chu_shi_hua(obj2,'lxx',38,'female')

obj3=People()
People.chu_shi_hua(obj3,'alex',38,'female')




# 方式四、为对象初始化自己独有的特征
class People:
country='China'
x=1

def __init__(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
obj.name = x
obj.age = y
obj.sex = z

def run(self):
print('----->', self)

obj1=People('egon',18,'male') #People.__init__(obj1,'egon',18,'male')
obj2=People('lxx',38,'female') #People.__init__(obj2,'lxx',38,'female')
obj3=People('alex',38,'female') #People.__init__(obj3,'alex',38,'female')


# __init__方法
# 强调:
# 1、该方法内可以有任意的python代码
# 2、一定不能有返回值
class People:
country='China'
x=1

def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male'
# if type(name) is not str:
# raise TypeError('名字必须是字符串类型')
obj.name = name
obj.age = age
obj.sex = sex


def run(self):
print('----->', self)


# obj1=People('egon',18,'male')
obj1=People(3537,18,'male')

# print(obj1.run)
# obj1.run() #People.run(obj1)
# print(People.run)

!!!__init__方法之为对象定制自己独有的特征

PS:

1. 站的角度不同,定义出的类是截然不同的,详见面向对象实战之需求分析

2. 现实中的类并不完全等于程序中的类,比如现实中的公司类,在程序中有时需要拆分成部门类,业务类......

3. 有时为了编程需求,程序中也可能会定义现实中不存在的类,比如策略类,现实中并不存在,但是在程序中却是一个很常见的类

#python为类内置的特殊属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

类的特殊属性(了解即可)

!!!补充说明:从代码级别看面向对象 !!!

#1、在没有学习类这个概念时,数据与功能是分离的
def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
conn.execute(sql)
return xxx


def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
conn.call_proc(sql)
return xxx

#每次调用都需要重复传入一堆参数
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')




#2、我们能想到的解决方法是,把这些变量都定义成全局变量
HOST=‘127.0.0.1’
PORT=3306
DB=‘db1’
CHARSET=‘utf8’

def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
conn.execute(sql)
return xxx


def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
conn.call_proc(sql)
return xxx

exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
exc2(HOST,PORT,DB,CHARSET,'存储过程的名字')


#3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用,然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合到一起的解决方法,这就是我们说的类了

class MySQLHandler:
def __init__(self,host,port,db,charset='utf8'):
self.host=host
self.port=port
self.db=db
self.charset=charset
def exc1(self,sql):
conn=connect(self.host,self.port,self.db,self.charset)
res=conn.execute(sql)
return res


def exc2(self,sql):
conn=connect(self.host,self.port,self.db,self.charset)
res=conn.call_proc(sql)
return res


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存储过程的名字')


#改进
class MySQLHandler:
def __init__(self,host,port,db,charset='utf8'):
self.host=host
self.port=port
self.db=db
self.charset=charset
self.conn=connect(self.host,self.port,self.db,self.charset)
def exc1(self,sql):
return self.conn.execute(sql)

def exc2(self,sql):
return self.conn.call_proc(sql)


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存储过程的名字')

数据与专门操作该数据的功能组合到一起

四、 属性查找
类有两种属性:数据属性和函数属性

1. 类的数据属性是所有对象共享的

2. 类的函数属性是绑定给对象用的

#类的数据属性是所有对象共享的,id都一样
print(id(GoodboyStudent.school))

print(id(s1.school))
print(id(s2.school))
print(id(s3.school))

'''
4377347328
4377347328
4377347328
4377347328
'''



#类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样
#ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准
print(GoodboyStudent.learn)
print(s1.learn)
print(s2.learn)
print(s3.learn)
'''
<function GoodboyStudent.learn at 0x1021329d8>
<bound method GoodboyStudent.learn of <__main__.GoodboyStudent object at 0x1021466d8>>
<bound method GoodboyStudent.learn of <__main__.GoodboyStudent object at 0x102146710>>
<bound method GoodboyStudent.learn of <__main__.GoodboyStudent object at 0x102146748>>
'''

在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常

练习:编写一个学生类,产生一堆学生对象,要求有一个计数器(属性),统计总共实例了多少个对象

五、 绑定到对象的方法的特殊之处

#改写
class GoodboyStudent:
school='Goodboy'
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def learn(self):
print('%s is learning' %self.name) #新增self.name

def eat(self):
print('%s is eating' %self.name)

def sleep(self):
print('%s is sleeping' %self.name)


s1=GoodboyStudent('李坦克','男',18)
s2=GoodboyStudent('王大炮','女',38)
s3=GoodboyStudent('牛榴弹','男',78)

类中定义的函数(没有被任何装饰器装饰的)是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数

GoodboyStudent.learn(s1) #李坦克 is learning
GoodboyStudent.learn(s2) #王大炮 is learning
GoodboyStudent.learn(s3) #牛榴弹 is learning

类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法

强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)

s1.learn() #等同于GoodboyStudent.learn(s1)
s2.learn() #等同于GoodboyStudent.learn(s2)
s3.learn() #等同于GoodboyStudent.learn(s3)

注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。



类即类型

  提示:python的class术语与c + +有一定区别,与
Modula - 3
更像。

  python中一切皆为对象,且python3中类与类型是一个概念,类型就是类

#类型dict就是类dict
>>> list
<class 'list'>

#实例化的到3个对象l1,l2,l3
>>> l1=list()
>>> l2=list()
>>> l3=list()

#三个对象都有绑定方法append,是相同的功能,但内存地址不同
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>

#操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3
>>> l1.append(3)
>>> l1
[3]
>>> l2
[]
>>> l3
[]
#调用类list.append(l3,111)等同于l3.append(111)
>>> list.append(l3,111) #l3.append(111)
>>> l3
[111]

六、 对象之间的交互
class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄;
camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia;
def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...;
self.nickname=nickname #为自己的盖伦起个别名;
self.aggressivity=aggressivity #英雄都有自己的攻击力;
self.life_value=life_value #英雄都有自己的生命值;
def attack(self,enemy): #普通攻击技能,enemy是敌人;
enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

我们可以仿照garen类再创建一个Riven类
class Riven:
camp='Noxus' #所有玩家的英雄(锐雯)的阵营都是Noxus;
def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54;
self.nickname=nickname #为自己的锐雯起个别名;
self.aggressivity=aggressivity #英雄都有自己的攻击力;
self.life_value=life_value #英雄都有自己的生命值;
def attack(self,enemy): #普通攻击技能,enemy是敌人;
enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

实例出俩英雄
>>> g1=Garen('草丛伦')
>>> r1=Riven('锐雯雯')

交互:锐雯雯攻击草丛伦,反之一样
>>> g1.life_value
455
>>> r1.attack(g1)
>>> g1.life_value
401

补充:

  garen_hero.Q()称为向garen_hero这个对象发送了一条消息,让他去执行Q这个功能,类似的有:

  garen_hero.W()

  garen_hero.E()

  garen_hero.R()

标签:__,name,People,Python,31,面向对象,对象,self,def
From: https://www.cnblogs.com/liu-zhijun/p/18402985

相关文章

  • 基于Web的会议记录与分享系统设计与实现---附源码83155
    目  录摘要第1章绪论1.1研究背景与意义1.2开发现状第2章相关技术介绍2.1JAVA技术2.2springboot框架2.3MySQL数据库第3章系统分析3.1可行性分析3.2功能需求分析3.2.1注册用户功能3.3非功能需求分析3.4安全性需求分析3.4.1系统的......
  • 基于yolov10的行人跌倒检测系统,支持图像检测,也支持视频和摄像实时检测(pytorch框架)【py
       更多目标检测和图像分类识别项目可看我主页其他文章功能演示:基于yolov10的行人跌倒检测系统,支持图像、视频和摄像实时检测【pytorch框架、python】_哔哩哔哩_bilibili(一)简介基于yolov10的行人跌倒检测系统是在pytorch框架下实现的,这是一个完整的项目,包括代码,数据集,训......
  • Python入门教程-Python 中的字符串及常用操作有哪些
    字符串是编程语言中最常见和最基础的数据类型之一。在Python中,字符串(string)是用于表示文本数据的序列。无论是处理用户输入、文件读写,还是处理网络数据,字符串都是编程中的关键工具之一。Python提供了许多方便的操作和方法来处理字符串数据。本文将带你从基础入门,详细介绍......
  • python入门
    引言        Python是一种高级编程语言,以其易读性和简洁性而闻名,非常适合初学者入门。Python广泛应用于各种领域,从网站开发到数据分析,再到人工智能和机器学习。本课时将带你走进Python的世界,了解Python的基本知识,并教你如何安装Python环境,使用IDLE或其他适......
  • 基于MicroPython的ESP8266与超声波传感器设计方案
        基于MicroPython的ESP8266与超声波传感器的设计方案:一、硬件准备1. ESP8266开发板(如NodeMCU)2. 超声波传感器(如HC-SR04)3. 杜邦线若干 二、硬件连接1. 将超声波传感器的VCC引脚和ESP8266的3.3V引脚,分别连接5V和3.3V电源。2. 将超声波传感器的GND引脚......
  • 掌握动态图表:使用Python的Matplotlib库实现动态数据可视化
    在数据可视化领域,Matplotlib库是Python中最流行和功能强大的工具之一。它能够生成各种静态图表,如散点图、折线图和柱状图等。然而,Matplotlib也提供了创建动态图表的功能,使得我们能够以动画的方式展示数据的变化趋势,从而更直观地理解数据。本文将介绍如何使用Matplotlib库创建动态图......
  • python之对象通过直接引用协作
    对象通过直接引用协作是面向对象设计中的一个概念,它指的是在一个对象内部直接持有另一个对象的引用,以便可以调用后者的方法或访问其属性。这种方式可以使得对象之间的通信和数据共享变得直接和简单。以下是对象通过直接引用协作的一些关键点:封装:每个对象都封装了自己的数据......
  • 如何使用Python实现自动初始化软件?再也不用一个一个打开了!
    前前言GitHub原创项目:Howto?https://github.com/ryan-zg/python-howto-autoinit     目前提交的代码较为简单,后续还会补充更新。前言        我在进行Java开发的过程中,每次打开电脑就需要启动很多软件,什么IDEA, VMware, Xshell, Nginx....等等。但是每......
  • STM32L431RC 光照度+温湿度+电机+ESP8266+腾讯云+CSDN 项目
    鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)STM32L431RC光照度+温湿度+电机+ESP8266+腾讯云+CSDN项目介绍1.项目概述......
  • 【2024潇湘夜雨】WIN11_PWK_21H2.22000.3147软件选装纯净特别版9.08
    【系统简介】=============================================================1.本次更新母盘来自WIN11_PWK_21H2.22000.3147(专业工作站版).2.全程离线精简、无人值守调用优化处理制作。部分优化适配系统可能要重启几次,即使显示适配失败也不要在意,可能部分优化不适用。3.OS版本号为2......