项目 | 面向过程 | 面向对象 |
---|---|---|
编程方法 | 自顶而下 | 自底而上 |
代码主体结构 | 程序=数据(变量)+算法(函数/过程) | 程序=对象+交互 |
数据操作主体 | 由函数/过程进行加工或展现 | 在对象的方法中加工或展现 |
模拟方法 | 通过函数/过程操纵表现世界的数据与状态 | 把世界描绘成具有主动性的对象进行交互(上帝视角) |
编程思想 | 代码实现处理数据的步骤 | 面向对象分析 |
优点 | 降低程序复杂度 | 解决了程序扩展性问题 |
理解对象:对象是具有自身的特征或能力
在计算机中,表现为对象具有解决问题所需的特征和能力(数据属性和方法属性)
Python面向对象编程:python中万物皆对象,每个对象都有三个属性id、type(类型)、value(值)
id:指向对象的地址(可以理解为内存中的位置)
is:身份运算符,
注意:id相同,则value一定相同;id不同,value可能相同
# 基于Python 3.7 IDLE
>>> a=1
>>> print(id(a)) #a的内存地址
1905867008
>>> print(type(a)) #a的类型
<class 'int'>
>>> print(a)
1
>>> b=2
>>> print(id(b))
1905867024
>>> print(type(b))
<class 'int'>
>>> print(a is b) #a和b的id(地址)不同
False
>>> print(a==b) #a和b的value(值)不同
False
>>> c=1
>>> print(id(c))
1905867008
>>> print(a is c) #a和c的id(地址)相同
True
>>> print(a==c) #a和c的value(值)相同
True
>>> x=500
>>> y=500
>>> print(x is y) #x和y的id(地址不同)可以尝试打印id
False
//ending
猜想:可能跟值的大小有关
类(class)与对象(object)是面向对象的核心概念。
类是对某一类事物的描述,是抽象的概念上的定义;对象是实际存在的属于该类事物的具体的个体,所以对象也被称为实例。
对象具有数据属性和方法属性
Python中对象(实例)本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法唯一绑定一个对象,同一个类的方法绑定到不同的对象上,属于不同的方法,内存地址都不会一样
在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性:而类中有两种属性:数据属性和函数属性,其中类的数据属性是共享给所有对象的,而类的函数属性是绑定到所有对象的。
创建一个对象(实例)就会创建一个对象(实例)的名称空间,存放对象(实例)的名字,称为对象(实例)的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类…最后都找不到就抛出异常。
.创建出类会产生名称空间,实例化对象也会产生名称空间。
用户自己定义的一个类,实际上就是定义了一个类型,类型与类是统一的。
用户先是从自己的命名空间找,如果找不大,在从类的命名空间找。
通过类来访问,访问的是函数,通过对象来访问,访问的是方法,在类内部定义的方式实际上是绑定到对象的身上来用的。
类的数据属性是大家共有的,而且大家的内部地址是一样的,用的就是一个类的函数属性是绑定到大家身上的,内部地址不一样,绑定方法指的是绑定到对象身上。
绑定方法:绑定到谁的身上,就是给谁用的,谁来调用就会自动把自己当做第一个参数传入。
定义在类内部的变量,是所有对象共有的,id全一样,
定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.fun()
会把obj本身当作 一个参数来传递。
在类内部定义的函数虽然可以由类来调用,但是并不是为了给类用的,在类内部定义的函数的目的就是为了绑定到对象身上的。
在类的内部来说,__init__是类的函数属性,但是对于对象来说,就是绑定方法。
命名空间的问题:先从对象的命名空间找,随后在从类的命名空间找,随后在从父类的命名 空间找。
类的相关方法(定义一个类,也会产生自己的名称空间):
方法名 | 功能 |
---|---|
类名.__name__ | 类的名字(字符串str) |
类名.__doc__ | 类的文档字符串 |
类名.__dict.__ | 类的字典属性、名称空间 |
类名.__module.__ | 类定义所在的模块 |
类名.__base__ | 类的第一个父类 |
类名.__bases__ | 类所有父类构成的元组 |
类名.__class__ | 实例对应的类(仅新式类中) |
经典类与新式类辨析:
Python 2.x:默认为经典类,继承object为新式类
Python 3.x:默认为新式类,自动继承object,不用写
经典类 继承为深度优先;新式类 继承为广度优先
构造函数在构造对象时自动被对象调用,对对象进行初始化。
//基本形式
class [ClassName]([Inherited class]):
def __init__(self,*args,**kwargs):
#使用构造函数初始化类,*args 普通动态参数
#**kwargs 关键字动态参数
例子:
#基于Python 3.7 IDLE
>>> class Car():
count = 0 #计数器
def __init__(self,name):
#self指针变量只想当前时刻正在处理的对象
self.name=name
#self.name=name的含义为将局部变量name的值发给当前时刻正在创建的对象中
#的name成员
Car.count += 1
>>> if __name__ =='__main__':
bmw=Car('BMW') #实例化对象
print(bmw.__dict__)
audi=Car('Audi')
print(audi.__dict__)
print(count)
{'name': 'BMW'}
{'name': 'Audi'}
2
类的继承是指从已有的类那里获取其已有的属性和方法。
特点:
继承的语法:
class ClassName: ([FatherClassName1,FatherClassName2])
重载的语法:
直接定义与父类同名的方法
修改父类的方法:
在重载的方法中调用父类方法(super关键字)
添加相应的业务逻辑
注意:多重继承时如何修改父类方法
例子:
>>> class Father():
def print(self):
print('I am Father')
>>> class Son(Father):
def print(self):
super().print() #调用父类方法
print("I am Son")
>>> if __name__=='__main__':
fa=Father()
fa.print()
print("----")
son=Son()
son.print()
I am Father
----
I am Father
I am Son
继承原理:MRO列表
对于每个类,python都会计算出一个方法解析顺序(MRO)序列–所有基类的线性顺序列表
#承接下方代码
print(SonClass.mro())
#结果
[<class '__main__.SonClass'>, <class '__main__.AbstractClass'>, <class 'object'>]
python通过在MRO列表中遍历,直到找到第一个匹配属性的类。
遍历原则:
抽象类与接口都是类概念的扩展。
抽象类是一个专门创建来做父类的类,类似于一个模板类,目的是根据他的格式来创建和修改新的类。
例子
import abc
class AbstractClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
#装饰器声明抽象方法
def absmethod(self):
pass
def commonmethod(self):
#抽象类中的普通方法
print("This is commonmethod")
class SonClass(AbstractClass):
def absmethod(self):
print("rewrite absmethod")
if __name__=='__main__':
sonclass=SonClass()
sonclass.absmethod()
print('----')
sonclass.commonmethod()
#结果
rewrite absmethod
----
This is commonmethod
接口:
在Java中,接口(Interface)的结构与抽象类类似,本身也具有数据成员和抽象方法,但也有不同:
但在Python中并无Interface的概念,但也可以用其他方法实现接口
组合的定义:一个类的某个属性成员是另一个类
例子:
class ClassA():
def __init__(self,name,num):
self.name = name
self.num = num
def statement(self):
print('This is %s ,We hava %s students'%(self.name,self.num))
class Sum():
def __init__(self,name,num):
self.name=name
self.info=ClassA(name,num)
if __name__== '__main__':
summary=Sum('classa',50)
summary.info.statement()
#结果
This is classa ,We hava 50 students
多态:一种类型具有多种类型的能力,
Python中的多态:通过继承实现(子类作为父类使用),子类重载父类的方法
动态语言与鸭子类型:
鸭子类型:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
动态语言:
多态的优点:
例子:
class Timer(object):
def run(self):
print("Start...")
def run_twice(a):
a.run()
a.run()
timer = Timer()
run_twice(timer)
#结果
Start...
Start...
面对对象编程中,为保证程序的安全,不能让外部类直接访问类内部的属性和方法,外部类要通过类内部定义的一些按钮才能访问类内部的成员
Python实现封装:
双下划线(访问控制符)实现隐藏属性,在内部可以直接访问,在外部则需要通过定义的按钮才能访问
例子:
class Car():
def __init__(self,name,type):
#构造函数被封装
self.__name=name
self.type=type
car='This is car' #没被封装,类外可以调用
__bus='This is bus'
def reset(self,name,type):
if not isinstance(name,str):
raise TypeError("Name must be string ")
if not isinstance(type,str):
raise TypeError("Type must be string")
self.__name=name #在类内可以调用
self.type=type
def print(self):
print('This is %s %s'%(self.__name,self.type))
if __name__== '__main__':
car=Car('Audi','A6')
car.print()
print(car.car)
car.reset('BMW','X1')
car.print()
print(car.__bus)
#结果
This is Audi A6
This is car
This is BMW X1
print(car.__bus) #(Line 26)
AttributeError: 'Car' object has no attribute '__bus'
一些参考的csdn博文:
https://blog.csdn.net/a2011480169/article/details/73087097
https://blog.csdn.net/flyDeDog/article/details/68925795
https://blog.csdn.net/Gscsd_T/article/details/78938116