面向对象编程学习笔记

面向对象的编程

面向过程的编程:
  • 核心:过程(过程指的是解决问题的步骤,机械式的思维方式)
  • 优点:将复杂的问题流程化,进而简单化
  • 缺点:可扩展性差
面向对象编程
  • 核心:对象(对象就是特征与技能的结合体)
  • 对象: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

多态与多态性

  • 同一种事物的多种形态
多态性:
  • 可以在不考虑对象的类型的情况下而直接使用对象
    • 如抽象类中只要是动物都有的属性,不管属于什么分类,都有这一个方法,可以直接使用
  • 多态性的好处:
  1. 增加类程序的灵活性
    • 以不变应万变,不论对象千变万化,都可以通过统一接口调用
  2. 增加类程序可扩展性
    • 通过继承父类创建类一个新类,使用者无需更改自己的代码,还是用同样的方法去调用
  • python崇尚的是一种鸭子类型

封装

如何实现属性的隐藏
class A:
	__x = 1 #_A__x=1
	
	def __init__(self,name):
		self.__name=name
		
	def __foo(self):
		print('run foo')
  • 特点:
  1. 在类外部无法直接使用
  2. 在类内部可以直接使用
  3. python并不真正隐藏,只是在类定义是进行了变形操作
  4. 子类无法覆盖父类__开头的属
封装的意义
  • 封装数据属性:明确区分内外,控制外部对隐藏的属性的操作行为

  • 封装方法:隔离复杂度

封装与扩展性
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. 参数1:字符串形式的命令
  2. 参数2:全局作用域(字典形式),如果不指定默认使用globals()
  3. 参数3:局部作用域(字典形式),如果不指定默认使用locals()
  • 对象可以怎么使用?
    • 都可以被引用:x = obj
    • 都可以当作函数的参数传入
    • 都可以当作函数的返回值
    • 都可以当作容器类
  • 产生类的类称之为元类,默认使用class定义的类,他们的元类是type
  • 定义类的三要素:
  1. 类名
  2. 类的基类
  3. 类的局部名称空间: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)
面向对象的软件开发
原文地址:https://www.cnblogs.com/wualin/p/9777548.html