面向对象的编程
面向过程的编程:
- 核心:过程(过程指的是解决问题的步骤,机械式的思维方式)
- 优点:将复杂的问题流程化,进而简单化
缺点:可扩展性差
面向对象编程
- 核心:对象(对象就是特征与技能的结合体)
- 对象:python中一切是对象
- 优点:可扩展性强
- 缺点:编程复杂度高
应用场景:用户需求经常变化,互联网应用,游戏,企业内部应用
类
- 类:就是一 系列对象相似的特征与技能的结合体(站在不同角度,得到的分类是不同的)
- 对象:特征与技能结合体
- 在现实世界中:一定先有对象,后有类
- 在程序中:一定得先定义类,后调用类来产生对象
- 查看名称空间:
stu1 = LufftStudent()
print(stu1.__dict__)
类:
class LuffyStudent:
school = 'luffycity' #数据属性
def learn(self):# 函数属性
print('is learing')
def eat(self):
print('is eating')
stu1 = LuffyStudent() #实例化对象
# # 查看类的名称空间
# print(LuffyStudent.__dict__)
# print(LuffyStudent.__dict__['school'])
# print(LuffyStudent.__dict__['learn'])
# 查看类的属性
#print(LuffyStudent.school) #LuffyStudent.__dict__['school']
# 增加类的属性
LuffyStudent.county = 'China'
# 删除
del LuffyStudent.county
# 改
LuffyStudent.school = 'Luffycity'
__init__方法
class LuffyStudent:
school = 'luffycity' #数据属性
def __init__(self,name,sex,age):# __init__方法用来对象定制对象独有的特征
self.Name = name
self.Sex = sex
self.Age = age
def learn(self):# 函数属性
print('is learing')
def eat(self):
print('is eating')
# 后产生的对象
stu1 = LuffyStudent('wualin','man',29)#LuffyStudent.__init__(stu1,'wualin','man',20)
# 加上__init__方法后,实例化步骤
# 1. 先产生一个空对象stu1
# 2. 触发LuffyStudent.__init__(stu1,'wualin','man',29)
#
# # 查
# print(stu1.Name)
# print(stu1.Sex)
# print(stu1.Age)
# # 改
# stu1.Name='520'
#
# # 删除
# del stu1.Name
#
# # 增
# stu1.class_name = 'python开发'
属性查找
类中的数据属性:是所有对象共有的
- 类中的函数属性:是绑定给对象,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传个self
class LuffyStudent:
school = 'luffycity' #数据属性
def __init__(self,name,sex,age):# __init__方法用来对象定制对象独有的特征
self.Name = name
self.Sex = sex
self.Age = age
def learn(self):# 函数属性
print('is learing')
def eat(self):
print('is eating')
# 后产生的对象
stu1 = LuffyStudent('wualin','man',29)
stu2 = LuffyStudent('张宝宝','man',19)
# 类的数据属性
print(stu1.school)
# 类的函数属性,类中函数属性是给对象使用的,谁调用就绑定给它使用,自动将对象传入第一个参数
stu1.learn()#learn(stu1)
#对象在访问一个属性的时候会先在对象里面的名称空间找,如果对象里面没有则去类里面找。不会到全局变量里面找
python中一切皆对象:
- 对象之间的交互:
class Girlun:
faction = 'Demasia'
def __init__(self,name,life,attack):
self.name = name
self.life = life
self.attack = attack
def attack_1(self,enemy):
enemy.life = enemy.life-self.attack
print('%s攻击了%s'%(self.name,enemy.name))
class Riwen:
faction = 'Demasia'
def __init__(self, name, life, attack):
self.name = name
self.life = life
self.attack = attack
def attack_1(self, enemy):
enemy.life = enemy.life - self.attack
print('%s攻击了%s' % (self.name, enemy.name))
g1 = Girlun('草丛伦',100,10)
r1 = Riwen('锐萌萌',80,20)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
继承与重用
- 继承指的是类与类之间的关系
- 查看继承自父类的哪些东西:
print(<类名>.__bases__)
- 继承示例:
class Hero:
def __init__(self,name,life,attack):
self.name = name
self.life = life
self.attack = attack
def attack_1(self,enemy):
print('%s攻击了%s'%(self.name,enemy.name))
class Griren(Hero):
pass
class Riven(Hero):
pass
g1 = Griren('盖伦',80,50)
r1 = Riven('锐雯',50,50)
g1.attack_1(r1)
派生
- 当子类中有需要的属性则不会去父类中查找
继承的实现原理:
- 原则:
- 子类会先余父类被检查
- 多个父类会根据他们在列表中的顺序被检查(从左到右)
- 如果下一个类存在两个合法的选择,会选择第一个父类
- MRO查找方法
print(<类名>.__mro__
在子类中重用父类的方法或属性
- 方式一:指名道姓,类名+方法(不依赖继承)
class Hero:
def __init__(self,name,life,attack):
self.name = name
self.life = life
self.attack = attack
def attack_1(self,enemy):
enemy.life -=self.attack
class Griren(Hero):
def attack_1(self,enemy):
Hero.attack_1(self,enemy) # 不依赖于继承
print('%s攻击了%s'%(self.name,enemy.name))
class Riven(Hero):
pass
g1 = Griren('盖伦',80,50)
r1 = Riven('锐雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
- 方式二:super()
- super()查找方法基于mro列表往后找
class Hero:
def __init__(self,name,life,attack):
self.name = name
self.life = life
self.attack = attack
def attack_1(self,enemy):
enemy.life -=self.attack
class Griren(Hero):
def __init__(self,name,life,attack,weapon):
super().__init__(name,life,attack)# 第一种写法,依赖于继承
def attack_1(self,enemy):
super(Griren,self).attack_1(enemy)# 第二种写法,依赖于继承
print('%s攻击了%s'%(self.name,enemy.name))
class Riven(Hero):
pass
g1 = Griren('盖伦',80,50,'大保健')
r1 = Riven('锐雯',100,50)
print(r1.life)
g1.attack_1(r1)
print(r1.life)
print(g1.__dict__)
组合
- 将两个类生成的实例对象组合在一起
抽象类与归一化
- 通过抽象类使子类中的方法名统一起来
- 抽象类只能被继承,不能实例化
import abc
class Animal(metaclass=abc.ABCMeta):# 通过抽象类使子类中的方法名统一起来
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
class People(Animal):
def run(self):
pass
def eat(self):
pass
class Pig(Animal):
def run(self):
pass
def eat(self):
pass
多态与多态性
同一种事物的多种形态
多态性:
- 可以在不考虑对象的类型的情况下而直接使用对象
- 如抽象类中只要是动物都有的属性,不管属于什么分类,都有这一个方法,可以直接使用
- 多态性的好处:
- 增加类程序的灵活性
- 以不变应万变,不论对象千变万化,都可以通过统一接口调用
- 增加类程序可扩展性
- 通过继承父类创建类一个新类,使用者无需更改自己的代码,还是用同样的方法去调用
- python崇尚的是一种鸭子类型
封装
如何实现属性的隐藏
class A:
__x = 1 #_A__x=1
def __init__(self,name):
self.__name=name
def __foo(self):
print('run foo')
- 特点:
- 在类外部无法直接使用
- 在类内部可以直接使用
- python并不真正隐藏,只是在类定义是进行了变形操作
- 子类无法覆盖父类__开头的属
封装的意义
封装数据属性:明确区分内外,控制外部对隐藏的属性的操作行为
封装方法:隔离复杂度
封装与扩展性
property的使用
propert:特性
class People:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,val):
if not isinstance(val,str):
print('val is not str')
return
self.__name = val
@name.deleter
def name(self):
print('不允许删除')
p = People('wualin')
print(p.name)
绑定方法与非绑定方法
- 绑定方法:
- 绑定给谁,就应该由谁来调用,谁来调用就把调用者当作第一个参数自动传入
绑定到对象的方法:在类内定义的没有被任务装饰器修饰的
绑定到类的方法:在类内部定义的装饰器classmethod修饰的方法
- 非绑定方法:不会自动传值,就是类中的普通工具,类和对象都可以使用
- 非绑定方法:不与类或者对象绑定
class Foo:
def __init__(self,name):
self.name = name
def tell(self):# 绑定到对象的函数
print('name:%s'%self.name)
@classmethod
def func(cls): #cls=Foo 绑定到类的方法
print(cls)
@staticmethod
def func1(x,y):#类中的普通函数
print(x+y)
f = Foo('wualin')
Foo.func1(1,2)
f.func1(1,3)
- 绑定方法与非绑定方法的实际应用场景
反射
- 通过字符串映射到对象的属性
hasattr(obj,'name')# 判断对象有没有'name'属性 obj.__dict__['name']
getattr(obj,'name') # 拿到对象的属性
setattr(obj,'name','wualin')#修改 obj.name = 'wualin'
delattr(obj,'age')# del obj.age
以上方法同样适用于类
- 反射的应用:
class Service:
def run(self):
while True:
cmd = input('>>>:').strip()
if hasattr(self,cmd):
func = getattr(self,cmd)
func()
def get(self):
print('get...')
def put(self):
print('put...')
obj = Service()
obj.run()
内置方法
- isinstance(obj,cls) 检查obj是否是类cls的对象
class Foo(object):
psss
obj = Foo()
isinstance(obj,Foo)
- issubclass(sub,super) 检查sub类是否是super的派生类(子类)
class Foo():
pass
class Bar(Foo):
pass
issubclass(Bar,Foo)
- item系列:
# item
class Foo():
def __init__(self,name):
self.name = name
def __getitem__(self, item):#查看
return self.__dict__.get(item)
def __setitem__(self, key, value):#增加
self.__dict__[key] = value
def __delitem__(self, key):#删除
del self.__dict__[key]
obj = Foo('wualin')
#操作字典的方式去操作obj对象
#查看
print(obj['name']) #obj.name
#增加
obj['age'] = 20 #obj.age = 20
print(obj['age'])
#删除
del obj['name'] #del obj.name
- str
class Foo():
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '<name:%s age:%s>'%(self.name,self.age)
f = Foo('wualin',20)
print(f)
- del:在对象被删除时先触发__del__,可自定义回收系统资源
class Open():
def __init__(self,filename):
print('Open...')
def __del__(self):
print('del...')
f = Open('a.txt')
print('---main---')
- call
class Foo:
def __call___(self,*args,**kwargs)
print(self)
print(args)
print(kwargs)
obj = ()
obj(1,2,3,a=1,b=2,c=3)#obj.__call__(obj,1,2,3,a=1,b=2,c=3)
元类介绍
- exec命令的使用:
- 参数1:字符串形式的命令
- 参数2:全局作用域(字典形式),如果不指定默认使用globals()
- 参数3:局部作用域(字典形式),如果不指定默认使用locals()
- 对象可以怎么使用?
- 都可以被引用:x = obj
- 都可以当作函数的参数传入
- 都可以当作函数的返回值
- 都可以当作容器类
- 产生类的类称之为元类,默认使用class定义的类,他们的元类是type
- 定义类的三要素:
- 类名
- 类的基类
- 类的局部名称空间:obj.__dict__()
- 定义类的两种方式:
方式1:class
- 方式2:type
class_name = 'Chinese' #类名 class_bases = (object,) #类的基类 class_body = ''' country = 'china' def __init__(self,name,age): self.name = name self.age = age def talk(self) print('%s is talking'$self.name) ''' class_dic = {}# 类的局部名称空间 exec(class_body,globals(),class_dic) Chinese1 = type(class_name,class_bases,clsaa_dic)
自定义元类控制类的行为
class Mymeta(type): ''' 给传入class_name添加首字母必须大写,否则抛出异常,如果定义类的元类是Mymeta(metaclass=),就必须遵循自定义规则 ''' def __init__(self,class_name,class_bases,class_dic): if not class_name.istitle(): raise TypeError('首字母大写') #raise主动抛出错误 class Chinese(object,metaclass=Mymeta): def __init__(self,name,age): self.name = name self.age = age def tall_info(self): print('Name: %s Age: %s'%(self.name,self.age))
自定义元类控制类的实例化行为
class Mymeta(type):
def __call__(self, *args, **kwargs):
'''
实例化类的步骤:
1. 生成obj对象
2. 初始化obj对象
3. 返回obj
:param args:
:param kwargs:
:return:
'''
obj = object.__new__(self)
self.__init__(obj,*args,*kwargs)
return obj
class Chinese(object,metaclass=Mymeta):
def __init__(self,name,age):
self.name = name
self.age = age
def tall_info(self):
print('Name: %s Age: %s'%(self.name,self.age))
obj = Chinese('WUALIN',20)
print(obj.__dict__)
自定义元类控制类的实例化行为的应用
- 单例模式:
class MySQL:
'''
假如一个类初始化属性都是一样的,可以使用单例模式节省内存空间
'''
__instance = None
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
@classmethod
def singleton(cls): #单例模式函数,生成实例化对象时调用该函数
if not cls.__instance:
obj=cls()
cls.__instance=obj
return cls.__instance
# 两次实例化对象内存地址是一样的
obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
- 通过元类实现单例模式:
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
self.__instance = None
def __call__(self, *args, **kwargs):
if not self.__instance:
obj = object.__new__(self)
self.__init__(obj)
self.__instance = obj
return self.__instance
class Mysql(object,metaclass=Mymeta):
'''
xxx
'''
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
obj1 = Mysql()
obj2 = Mysql()
print(obj1 is obj2)