面向过程编程:
- 导入外部库
- 设计全局变量
- 写一个函数实现某个功能,将得到的结果往下一个函数传递,并作为下一个函数的起始条件
- 写一个函数完成某个功能,将得到的结果往下一个函数传递,并作为下一个函数的起始条件
- 写一个函数完成某个功能,将得到的结果往下一个函数传递,并作为下一个函数的起始条件
- …
- 写一个main函数作为程序入口
面向过程变成的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么然后干什么……
基于面向过程编程的思想编写程序好比在设计一条流水线,是一种机械式的思维方式。
1. 优点:复杂的问题流程化、进而简单化
2. 缺点:扩展性差
面向对象编程:
- 导入各种外部库
- 设计各种全局变量
- 决定你要的类
- 给每个类提供完整的一组操作
- 明确地使用继承来表现不同类之间的共同点
- 根据需要,决定是否写一个main函数作为程序入口
面向对象的程序设计:核心是对象二字,对象是特征与功能的结合体,简单说一个公司要拓展海外业务,需要有外贸专业技能的人,那么HR招聘到的外贸专业人才就能称之为"对象",特征即是他的岗位或姓名,功能:外贸专业技能,公司业务拓展,便可以很方便通过他的特征来调用他的功能,比如:安排某某某参加外贸商务谈判。
优点:可扩展性强(参考下图)
缺点:编程的复杂度要高于面向过程
类的意思:种类、分类、类别
对象是特征与技能的结合体,多个相似功能的对象(参考下图),可以划分为一类,因此给出类的定义:类就是一系列对象相似的特征与技能的结合体。
在现实世界中:先有一个个具体存在的对象,然后随着人类文明的发展才了分类的概念,既然现实世界中有类这个概念,Python程序中也一定有类这个概念,和现实世界不同的是在Python程序中:必须先定义类,然后调用类来产生对象。
定义类:
# 定义一个学生类
# 相似特征: 学校
# 相似技能:学习、选课
# 不同点:姓名、年龄、性别
class Student:
school='python训练营'
def learn(self):
print('%s 在%s 学习 !'%(self, Student.school))
def Elective(self):
print('is Electives')
# print('=====================run') # 类体代码在类的定义阶段就会立即执行
# 查看属性
print(Student.school) # 数据属性
print(Student.learn) # 函数属性
Student.learn('Jasn') # 类的函数属性调用
# 增加属性
Student.country = 'China'
print(Student.country)
# 修改属性
Student.school = 'python训练' # 重新赋值
print(Student.school)
# 删除属性
del Student.country
print(Student.country) # 内存不存在conutry,导致报错
定义对象
调用类即可产生对象,调用类的过程,又称为类的实例化,实例化的结果称为类的对象/实例
stu1=Student() # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
print('学生一的学校是:',stu1.school)
stu2=Student() # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
print('学生二的学校是',stu2.school)
结果:
学生一的学校是: python训练营
学生二的学校是: python训练营
class Student:
school='python训练营'
def learn(self):
print('%s 在%s 学习 !'%(self, Student.school))
def Elective(self):
print('is Electives')
stu1 = Student() # 学生一
stu2 = Student() # 学生二
stu3 = Student() # 学生三
对于上述的学生类,如果类的属性改了,则其他对象的属性也会随之改变:
Student.school = 'Java训练营'
print(stu1.school)
结果:
Java训练营
对象本质类似于类,也是一个名称空间,但是对象的名称空间存放对象独有的名字,而类中存放的是对象们共有的名字。因此我们可以直接为对象单独定制名字。
stu1.name = '金鞍少年'
stu1.age = 18
stu1.gender = 'male'
print(stu1,id(stu1))
print(stu2,id(stu2))
print(stu3,id(stu3))
'''
<__main__.Student object at 0x000001E88EC95550> 2098339599696
<__main__.Student object at 0x000001E88ECA46D0> 2098339661520
<__main__.Student object at 0x000001E88ECD10D0> 2098339844304
'''
print(stu1.name, stu1.age, stu1.gender) # 金鞍少年 18 male
print(stu1.__dict__) # {'name': '金鞍少年', 'age': 18, 'gender': 'male'}
try:
print(stu2.name, stu2.age, stu2.gender)
except Exception as e:
print(e) # 'Student' object has no attribute 'name'
'''
尽管stu1\stu2\stu3 都属于Student学生类的对象,但是却属于不同的内存地址,也就是对象私有化属性不能被其他对象引用。
'''
def init(obj, name, age, sex):
obj.name = name
obj.age = age
obj.sex = sex
init(stu1, '金鞍少年', 18, 'male')
print(stu1.name, stu1.age, stu1.sex)
结果:
金鞍少年 18 male
使用上述方法虽然让我们定制属性更简单,但是还是太麻烦了,如果可以在实例化对象的时候自动触发定时属性,那就更方便了,因此可以使用类的__init__方法。
class Student:
school='python训练营'
def __init__(self,name,age,sex): # 在实例化(调用)时候会触发
self.Name=name
self.Age=age
self.Sex=sex
def learn(self,x,y):
print('%s is learning!'%self.Name)
print(x,y)
def Elective(self):
print('%s is Electives'%self.Name)
# 调用类 =================> 过程称之为实例化对象
# 1、会得到一个返回值,即对象,该对象是一个空对象,并将空对象当成self参数传入函数中
stu1 = Student('agon',18,'男') # stu1.Name,stu1.Age,stu1.Sex
stu2 = Student('nancy',17,'女')
stu3 = Student('Jasn',17,'男')
print(stu1.school,stu1.Name,stu1.Age,stu1.Sex)
print(stu2.school,stu2.Name,stu2.Age,stu2.Sex)
print(stu3.school,stu3.Name,stu3.Age,stu3.Sex)
# python训练营 金鞍少年 18 男
# python训练营 nancy 17 女
# python训练营 Jasn 17 男
总结:
通过上述现象可以发现,调用类时发生两件事:
1、创造一个空对象
2、自动触发类中__init__功能的执行,将stu1以及调用类括号内的参数一同传入
查找一个对象属性顺序是,先找对象自己的__dict__,再找类的,类中没有则会报错。即对象的属性查找顺序为:自身=== > 类 ====> 报错
class Student:
school='python训练营'
def __init__(self,name,age,sex):
self.Name=name
self.Age=age
self.Sex=sex
def learn(self,x,y):
print('%s is learning!'%self.Name)
print(x,y)
stu1 = Student('金鞍少年',18,'男')
stu2 = Student('nancy',17,'女')
stu3 = Student('Jasn',17,'男')
类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,需要几个参数即传几个参数。
stu1.learn(2020,'03') # 对象stu1调用learn函数属性,这个时候stu1即绑定了类的函数属性,将对象所独有的数据属性,当作参数传入类的函数体中
'''结果:
金鞍少年 is learning!
2020 03
'''
stu1 = Student('金鞍少年',18,'男') # stu1.Name,stu1.Age,stu1.Sex
stu2 = Student('nancy',17,'女')
stu3 = Student('Jasn',17,'男')
print(id(stu1.__init__('金鞍少年',18,'男')),id(stu2.__init__('nancy',17,'女')),id(Student.__init__))
# 140709446424704 140709446424704 1748118389088
print(id(stu1.Elective),id(stu2.Elective),id(stu3.Elective),id(Student.Elective))
# 2805656645696 2805656645696 2805656645696 2805688025872
print(id(stu1.Name), id(stu2.Name), id(stu3.Name))
# 2419005965968 2419006535664 2419006535792
# l1=[1,2,3,4,5] # 实际上是: 11=list(list[1,2,3,4])
l1 = [1, 2, 3, 4, 5]
l2 = [1, 2, 3, 4, 5]
# l1.append(6) # 有两个参数 self 和 x ,等同于 list.append(l1,6)
list.append(l1, 6)
print(l1)
print(list.append) #
# 绑定方法概念
l1.append('a')
l2.append('b')
# 两个append调用的方法都是一样的,但是执行解决却不同 ,研究这个案例,加深对绑定方法的理解
# 在python中,类即是类型。
'''
从代码级别看面对对象
# 代码是伪代码,connect功能没写,主要是演示面对对象的好处
'''
#1、在没有学习类这个概念时,数据与功能是分离的
def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
res = conn.execute(sql)
return res
def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
res= conn.call_proc(proc_name)
return res
#每次调用都需要重复传入一堆参数
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)
res = conn.execute(sql)
return res
def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
res= conn.call_proc(proc_name)
return res
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('存储过程的名字')
# 数据与专门操作该数据的功能组合到一起