python之面向对象编程
一、面向过程的概念
1.面向过程是什么?
面向过程的核心是‘过程’二字,解决问题的流程,分成几个部分,先干什么,再干什么,最后干什么。
2.面向过程的优缺点:
优点:把复杂的问题简单化,进而流程化
缺点:牵一发而动全身,扩展性差、可维护性差
3.应用场景:
应用于对于扩展性需求比较低的场景,比如应用程序的安装等。
二、面向对象的概念
1.面向对象是什么?
面向对象的核心就是‘对象’二字
2.对象是什么?
在现实生活中:一切皆对象(人,动植物,各种物品...)
在程序中:定义为特征与技能的结合体。
举个例子:我不是孙悟空,因为我没有孙悟空的外表(特征),我也没有孙悟空的那些技能。
3.面向对象的优缺点
优点:拓展性强,可维护性强
缺点:编程复杂度高
4.面向对象的应用场景
对拓展性要求高的,比如微信、QQ等等程序,经常需要更新功能的
三、类
1.类的产生
类是一系列对象的相似特征与相似技能的结合体,一般类名的首字母都是大写。
站在不同的角度,划分的类不一定是一样的。举个例子,人跟猪是一类,都属于动物类。
面向对象的基本思路就是把程序中需要的数据和功能都先整合到对象里面,然后每个对象共同的数据和功能整合到一起,就定义为类。
类的产生其实就是为了给对象提供属性和功能的。
2.类跟对象的产生顺序
在现实生活中:先有对象才有类
在程序中:必须先定义类,然后调用类才会产生对象
3.类的语法格式
class 类名():
函数体代码
4.定义类内部原理是什么呢?
定义类之后立即会产生一个类的全局名称空间
接着执行类内部的函数体代码,产生的名字全部存在类的全局名称空间
接着把类的全局名称空间绑定给__dict__
5.类和对象的关系
调用类就会产生对象,对象使用__dict__默认产生一个空字典。
调用类的过程我们称之为‘实例化’,产生的对象称之为‘实例’。我们可以用打印__dict__的方式查看类这个容器内盛放的东西或者对象的名称空间。
对象名 = 类()
print(对象名.dict)
print(类名.dict)
6.类的作用
1.属性引用:类名.属性
2.实例化:对象名 = 类名(参数) # 参数可以没有
7.给对象添加参数生成独有数据
在类体增加一个def init(参数):无返回值
8.调用类内部原理
得到一个空对象
调用了类名.dict(参数)
得到一个初始化的结果(自动执行传参后的__init__函数)
9.属性与方法的访问
1.类属性:在类中写的属性
2.对象属性:在对象自己的名称空间中写的属性
3.类属性访问:
查:类名.属性
增:类名.属性 = 值
改:类名.属性 = 新的值
删:del 类名.属性
4.对象属性访问:
查:对象名.属性
增:对象名.属性 = 值
改:对象名.属性 = 新的值
删:del 对象名.属性
5.类的方法访问
类中的方法,类可以调用,对象也可以调用,但是类调用需要把对象当参数传入,而对象调用可以自动把自己当第一个参数传入,所以推荐对象调用。
四、小练习
1.题目:定义一个类,产生多个对象;统计产生了多少个对象。
解题思路:多次调用类产生对象,调用类会触发自动执行__init__方法。统计个数需要用到计数器。想办法把计数器在__init__方法中每次调用就+1
解题:
class Aaa(): # 定义一个类
count = 0 # 定义计数器 一个属性
A11 = 99 # 一个属性
def __init__(self, aa, bb): # 一个方法
self.aa = aa # 方法中的属性
self.bb = bb # 方法中的属性
Aaa.count += 1 # 类中的计数器+=1 ,即每次调用改方法执行到这里计数器就+1,修改了类属性
A1 = Aaa(00, 11) # 调用1次,生成一个对象
A2 = Aaa(10, 11) # 调用2次,生成第二个对象
A3 = Aaa(11, 12) # 调用3次,生成第三个对象
print(Aaa.count) # 打印类属性
2.题目:定义一个英雄类,包含生命值和攻击力。产生两个对象(英雄),两个对象互相攻击,掉血。
解题思路:定义一个类,类调用两次产生两个对象(英雄),定制不同的参数。
五、绑定方法
绑定方法有两种:一种绑定给对象,另一种绑定给类。
绑定给对象:对象点的方式调用时会自动传入对象;类点的方式调用,需要主动传入对象。
绑定给类:语法糖@classmethod在方法上面,类点的方式调用会自动传入类;对象也可以直接用点的方式调用。
非绑定方法:即静态方法,语法糖@staticmethod在方法上,类和对象都通过点的方式调用。
1.绑定方法给对象:
# 绑定给对象:
class Teacher():
school = '老男孩'
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
print('老师:%s,年龄:%s' % (self.name, self.age))
teacher1 = Teacher('jason', 20)
teacher2 = Teacher('ly', 18)
teacher1.get_name() # 对象调用方法,会自动把自己当成参数传入
teacher2.get_name() # 对象调用方法,会自动把自己当成参数传入
2.绑定方法给类:
# 绑定给类:
IP = '127.0.0.1'
PORT = 81
class mySQL():
school = '老男孩'
def __init__(self, IP, PORT):
self.IP = IP
self.PORT = PORT
@classmethod # 把语法糖下面的方法绑定给类,以后类调用该方法,会自动把类名当成第一个参数传过来
def tell_info(cls): # tell_info(mySQL)
obj = cls(IP, PORT) # obj = mySQL(IP, PORT)
return obj
obj = mySQL.tell_info() # 把类名mySQL传入方法tell_info,调用类执行__init__生成有数据的对象返回,用一个变量obj接收返回值
print(obj.IP) # 访问对象obj的属性IP
六、非绑定方法(静态方法)
类中的方法即不绑定给类,也不绑定给对象,就称为非绑定方法,也叫静态方法。即在方法顶上加一个@staticmethod.
# 静态方法
class Teacher():
def __init__(self, name, age):
self.name = name
self.age = age
@staticmethod # 加一个staticmethod静态方法语法糖,下面的方法不绑定给类或者对象,类和对象都可以直接通过.方法名()调用
def aaa():
x = 10
return x
t1 = Teacher('jason', 20)
print(Teacher.aaa())
print(t1.aaa())
七、隐藏属性或者方法
1.如何隐藏:在属性名或者方法名前面加__
2.为何隐藏:类(对象)中的属性,类内部可以使用,外部也可以使用。隐藏属性的目的主要是为了严格控制类外部对类内部属性的修改。
3.隐藏属性内部发生了什么?
在类的定义阶段,发生了语法上的变形:类名__属性名
隐藏对类外部隐藏,不对内部隐藏(内部要用也是要加_)
只有在类定义阶段发生,其他情况不发生变形。
# 隐藏
class Teacher():
__school = '老男孩' # 属性名前面用__隐藏
def __init__(self, name, age):
self.name = name
self.age = age
def get_school(self): # 定义一个方法拿学校返回值
return self.__school # 对内部不隐藏
def set_school(self, v): # 定义一个方法用来修改学校
if not isinstance(v, str):
return '输入不合法'
self.__school = v
return self.__school
t1 = Teacher('jason', 20) # 调用类产生对象
print(Teacher.__dict__) # 查看类的名称空间都有些什么名字
print(Teacher._Teacher__school) # 外部真要访问也能通过这种方式访问
print(t1.get_school()) # 外部访问可以通过调用类内部的方法接收返回值查看
print(t1.set_school(123)) # 对象调用方法传入修改后的值123不合法
print(t1.set_school('新东方')) # 对象调用方法此传入修改后的值'新东方'合法修改
八、装饰器
1.@property装饰器:把方法伪装成属性
2.@属性名.setter:把方法伪装成修改属性
3.@属性名.deleter:把方法伪装成删除属性
# 装饰器
class Teacher():
school = '老男孩'
def __init__(self, name, age):
self.__name = name
self.age = age
@property # 把方法伪装成属性
def name(self):
return self.__name
@name.setter # 修改装饰器:把方法伪装成属性
def name(self, v):
if not isinstance(v, str):
return '输入不合法'
self.__name = v
return self.__name
@name.deleter # 删除装饰器
def name(self):
del self.__name
t1 = Teacher('jason', 20) # 调用类产生对象
print(t1.name) # 用之前一样的方法访问属性,但是实际上是在调用方法 def name(self):
t1.name = '111' # 用之前一样的修改方法,但是实际上是在调用方法 def name(self, v):
print(t1.name)
del t1.name # 用之前一样的删除方法,但实际上是在调用方法 def name(self):
print(t1.__dict__) # 查看对象t1的名称空间
# 装饰器
class Teacher():
school = '老男孩'
def __init__(self, name, age):
self.__name = name
self.age = age
def get_name(self):
return self.__name
def set_name(self, v):
if not isinstance(v, str):
return '输入不合法'
self.__name = v
return self.__name
def del_name(self):
del self.__name
name = property(get_name, set_name, del_name) # 如果不在每个方法顶上加装饰器,也可以用这个方法
t1 = Teacher('jason', 20) # 调用类产生对象
print(t1.__dict__) # 查看对象t1的名称空间
print(t1.name) # 用之前一样的方法访问属性,但是实际上是在调用方法 def name(self):
t1.name = '111' # 用之前一样的修改方法,但是实际上是在调用方法 def name(self, v):
print(t1.name)
del t1.name # 用之前一样的删除方法,但实际上是在调用方法 def name(self):
print(t1.__dict__) # 查看对象t1的名称空间