python面向对象

面向过程的编程方式更注重步骤,不注重分工,在需求复杂时开发难度大,比如游戏方向,太多内容和逻辑,拿比较简单的植物大战僵尸为例,如果考虑不同状态下所有植物和僵尸的动作,很难基于过程分析,开发难度是很大的,由此产生了面向对象的编程思想,相较函数,对象是更大的封装,编程时先确定职责,产生对象,再确定具体方法。

基本操作

类是具有相同特征或行为的事务的统称,是抽象的,并不能直接使用,用class定义,内部包含属性和方法,是创建对象的模板。

构造函数为def __init__(参数):用于初始化内部属性,添加属性可在任意函数中实现,只是在init方法中时可在调用时自动执行,与Java和C不同,属性无需提前声明。

可以通过__dict__[属性名].方法查看成员,添加也可以使用.方法,但添加属性最好在类的内部定义,便于维护。

对象

对象是由类创造出来的具体存在,创建方法为对象=类名(),实例化时先开辟对象空间,自动执行构造方法,并将内存地址传给init方法的第一个位置的参数self,对象可以通过.方法查看和修改变量。

对象找属性的顺序为对象空间=>类空间=>父类。

类的关系

关联、依赖、聚合、组合,实质都一样,是类对其他类进行操作,主要形式是将类作为参数在内部方法中传递。

类的成员

由静态字段和动态方法构成,__双下划线修饰的是私有成员,只能在类的内部访问,公有成员任何位置都能访问。

类的方法

就是写在类内的函数,可以通过装饰器进行修饰:
@classmethod修饰将类本身作为对象操作的方法,示例代码如下:

class animal():
	num=1
	def eat(self,obj):
		obj.eat()
		
	@classmethod
	def add(self):
		self.num=self.num+1
		print("num added already")

animal.add()		
print(animal.num)

此时类中的num已经变为2,对象生成后并不影响类,但通过类方法装饰的方法可以直接对类本身进行修改,让类具有记忆力,让对对象的操作持久化到类中。

@staticmethod装饰器修饰的方法为静态方法,该方法不涉及类中的属性和方法,是单纯独立的函数,仅仅托关于类的命名空间中,便于使用和维护,本质和定义在类外的函数没有区别。

函数是显式传递数据,方法是隐式传递数据,Java中只有方法,C中只有函数。

特殊属性

@property修饰的方法,在执行函数后只返回值,将方法作为一个成员返回,如:

class animal():
	a=3
	b=2
	@property
	def add(self):
		return self.a+self.b

a=animal()
print(a.add)

如此装饰的方法,使得用户不知道其内部是由函数运算的,但现在是没想到有啥用处。

也可以使用@成员名.setter@成员名.deleter定义修改和删除的方法,在触发时自动执行。

isinstance(a,b)判断a是否是b类派生类中实例化的对象
sisubclass(a,b)判断a是否是b的派生类或派生类的派生类,继承关系更深的判断

三大特征

继承,封装,多态是面向对象的三大特征,功能分别为:
继承:实现代码的复用
封装:将属性和方法封装到一个抽象的类中
多态:不同对象调用相同的方法而产生不同的执行结果

封装

这里的封装没啥好说的,是面向对象的基本要求,抽象类内定义属性和方法,实例化后才能使用,主要介绍一下继承和多态,其中多态最为重要。

但也有一个方法要学习,为了统一命名,限制派生类必须重写该方法时,可让基类方法抛出NotlmplementError异常,如果派生类未重写时则直接报错,用于限制类中命名规范,或引入抽象类,借助第三方模块from abc import ABCMeta,abctractmethod实现,设置抽象方法,要求子类必须重写,与Java中的抽象类和接口类似。

继承

继承方法为class 类名(父类名):,此时新定义的类就具备了父类的所有方法和属性,生成的对象可以直接调用,基类不继承时python规定默认继承object类,重写后若要使用父类方法,通过父类名.方法super().方法实现。

一个子类继承多个父类为多继承,实现方法为class 类名(父类名,父类名),多个父类有相同方法时,按继承顺序优先继承,具体确定顺序由一套mro序列实现,在类创建时计算。

私有属性或方法,不希望被子类继承或外部访问的成员使用该方法,具体实现为__方法名,子类和外界不可直接访问,可通过父类公用方法间接访问。

多态

在这我首先复习了一下Java中学习的多态,当时的原话是允许父类的引用指向子类的对象,这次学的比较不是开发课程,但核心是一致的,就是不同的子类调用相同的方法产生不同的结果,也有可以通过父类方法的参数中有对象来实现,比如def work(self,obj):obj.work()就可以实现调用obj对象的方法,通过对象进参数的手段,实现调用相同方法而产生不同的结果,各种手段形式不同,而目标相同,就是同一个方法产生不同的结果,那这里有一个疑问,重载算不算多态呢?

这里我又去查了一下,感觉我上面说的多态并不严谨,一般的多态是必须要有继承关系,即子类继承父类,子类覆盖父类,父类指向子类这样一个过程,重载和上面提到的实现手段是面向过程的,而非严格意义上的多态,故一般的多态,还应该是父类对象接受子类实例实现的,可在这里我又有疑问了,python是弱类型的语言,父类子类全看实例化对象本身,无法人为规定,该怎么用父类去接收子类对象呢?经过学习,用如下代码示例:

class animal():
	def eat(self,obj):
		obj.eat()
	
class dog(animal):
	def eat(self):
		print("dog eats")
		
class cat(animal):
	def eat(self):
		print("cat eat")
		
dog=dog() 
a=animal()
a.eat(dog) # 多态调用

看来还是实现的手段不同,针对弱类型的python,通过将对象传入基类方法作为参数,即可实现多态,严格意义上的多态只存在于强类型的Java和C中,python使用鸭子类型,即一只鸟看着像鸭子,叫起来像鸭子,那它就是鸭子,所以我们尽可以使用函数来接收鸭子对象,调用他走和叫的方法,如:def eat(obj): obj.eat()此时传入对象即可调用不同的方法。
这样的话好像没有继承关系,直接在不同的类中调用其他类的方法就可以实现多态了,经过尝试,删除doganimal的继承后,函数照样可以执行正确,真是只要能干鸭子的活那他就是鸭子,到底是谁的子类python并不在乎。

反射

通过字符串操作对象相关属性的方法,以往对相关属性操作是通过.__dict__方法获取,通过反射可以使用如下方法:

hasatter(obj,name)  # 判断对象中是否有name的属性
getatter(obj,name)	# 获取名为name的成员
setatter(obj,name,value)	# 设置成员的值
delatter(obj,name)	# 删除名为name的属性  上述方法的名称均通过字符串形式传递

用该方法可以实现字符串本身与对象的传递,比如菜单的选择,用输入的字符串直接与成员相匹配,减少代码量的同时确保完整覆盖逻辑,避免逻辑缺失,简单示例如下:

class animal():
	a=3
	b=2
	
a=animal()	
print(getattr(a,'a'))

双下方法

重写针对对象的操作。

__len__		len()时触发
__str__		打印对象时触发
__call__		对象()时执行
__del__		内存释放时自动触发
__init__		实例化对象时触发
__eq__		判断相等时触发
__new__ 	创建时开辟内存空间触发,限于init方法

上述方法类似于对象操作时对操作符的重载,也表明了python在执行方法和操作符时本质上还是调用的底层方法。

总结

python是一门面向对象的语言,本章才刚刚接触到,最重要的多态的概念,但在python中,因为其弱类型的语言特质,缺少了一定形式而没有那么优雅,转而使用鸭子类型,只要将对象实例传入方法中就可以实现同名称不同结果的效果,并不在乎其具体继承关系。

此外都是Java和C++的低配版,确实开发效率高,基本只要考虑本身的逻辑,而很少无关的硬性规定,优雅优雅。

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值