面向过程
所谓过程就是我们解决问题的步骤,一步一步的按照流程走,有先后之分
整个设计就好比流水线,思维上比较机械化
优缺点:
-
优点
- 复杂的问题流程化,将问题分解简化
-
缺点
- 拓展性不好
面向对象
核心是对象
正式的来说:
- 对象是一个数据以及相关行为的集合
- 面向对象是功能上指向建模对象
通过数据和行为方式来描述交互对象的集合
在python中,一切皆为对象
面向对象的优缺点:
- 优点
- 解决程序的拓展性
- 缺点
- 就是复杂度远高于面向过程
- 交互式解决问题,无法准确预测结果
在现实世界中,以我们为例
object1:
Tom
特征:
school=zucc
name=Tom
age=20
sex=male
技能:
eat
study
sleep
object2:
Jack
特征:
school=zucc
name=Jack
age=21
sex=male
技能:
eat
study
sleep
类就是类别、种类
对象就是特征和技能的统一体
类则是这一系列对象的特征和技能的结合
对于现实世界,先有个体(即对象),才有类别;但对于程序,必须先有类,然后才有对象的
面向对象编程
OOP(object oriented programming)
是一种程序设计思想。OOP把对象作为程序的一个基本单元,一个对象就包含了数据和操作数据的函数
在python中,所有数据类型都可以视为对象,同时,我们也可以自定义对象
自定义的对象的数据类型就是面向对象中类(class)的概念
Demo:
假如要处理我们的成绩,为了表示学生的成绩:
- 面向过程的方式
stu1={'name':'Tom','score':99}
stu1={'name':'Jack','score':90}
利用函数来实现
def find_score(stu):
print(stu['name'],':',stu['score'])
class student:
def __init__(self,name,age,sex,school):
self.name=name
self.age=age
self.sex=sex
self.school=school
def find(self):
print(self.name,':',self.age,self.sex,self.school)
stu1=student('tom',20,'male','zucc')
stu1.find()
tom : 20 male zucc
常见的概念
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- **数据成员:**类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- **局部变量:**定义在方法中的变量,只作用于当前实例的类。
- **实例变量:**在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- **实例化:**创建一个类的实例,类的具体对象。
- **方法:**类中定义的函数。
- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
面向对象相关基本函数
isinstance 和 issubclass
isinstance(obj,class) 检查obj是否是这个cls的对象
issubclass(cls(子),cls(父)) 检查是否是继承关系
class Foo:
pass
foo=Foo()
print(isinstance(foo,Foo))
print(isinstance(1,int))
True
True
class Foo:
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo))
True
反射
所谓反射,是指程序可以访问、检测和修改它本身状态或者行为的一种能力(自省)
在python中,面向对象中的反射是指通过字符串的形式操作对象的相关属性
四个可以实现自省的函数
-
hasattr
-
hasattr(*arg,**kwargs)
-
getattr
- getattr(obj,name,default=None)
-
setattr
-
setattr(obj,name,value)
-
delattr
- delattr(obj,name)
class Foo:
f='类的静态变量'
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('hello,%s'%self.name)
obj=Foo('Tom',22)
# 检测是否含有某个属性
print(hasattr(obj,'name'))
# 获取属性
gt=getattr(obj,'name')
print(gt)
gtf=getattr(obj,'say')
gtf()
gtf1=getattr(obj,'hello') # 不存在报错
True
Tom
hello,Tom
gtf1=getattr(obj,'hello') # 不存在报错
AttributeError: 'Foo' object has no attribute 'hello'
print(obj.__dict__)
# 设置属性
setattr(obj,'good man',True)
setattr(obj,'show_name',lambda self:self.name+'good man')
print(obj.__dict__)
print(obj.show_name(obj))
# 删除属性
delattr(obj,'show_name')
print(obj.__dict__)
delattr(obj,'a') # 不存在会报错
{'name': 'Tom', 'age': 22}
{'name': 'Tom', 'age': 22, 'good man': True, 'show_name': <function <lambda> at 0x0000016D3E0C1E18>}
Tomgood man
{'name': 'Tom', 'age': 22, 'good man': True}
delattr(obj,'a')
AttributeError: a
联想,字符串,列表,元组可以通过索引值引用值,字典可以通过关键字引用值,用了[]
item系列
class Foo:
def __init__(self,name):
self.name=name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key]=value
def __delitem__(self, key):
print('del obj[key]时:')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时:')
self.__dict__.pop(item)
obj1=Foo('Tom')
obj1['age']=18
obj1['age1']=19
print(obj1.__dict__)
del obj1['age']
del obj1.age1
print(obj1.__dict__)
{'name': 'Tom', 'age': 18, 'age1': 19}
del obj[key]时:
del obj.key时:
{'name': 'Tom'}
__del__
析构方法,当对象在内存中被释放,就会自动触发执行。
一般不需要自定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
print('执行了del函数')
obj=Foo()
del obj
执行了del函数
__str__
- 如果直接print打印对象,会看到创建对象的内存地址
- 当我们使用print(xxx)时,输出对象,如果对象中定义了
__str__
方法时,会返回return后的结果
class Cat:
def __init__(self,new_name,new_age):
self.name=new_name
self.age=new_age
def __str__(self):
return '名字是:%s,年龄是:%s'%(self.name,self.age)
obj=Cat('Tom',3)
print(obj)
名字是:Tom,年龄是:3