首先,我们先借着菜鸟教程的定义来大致过一遍面向对象的定义:
然后,阐述一下我的个人理解(可能不完善不准确,大家看看就完事儿了):
我所理解的面向对象,只不过是一种解决问题的思路,例如我现在是一个创世主,我要开始制作一个世界了。
我选择面向对象的思路来创造,于是我决定先创建动物(基类),我捏了狗、鸟、虎(狗、鸟、虎都属于动物的派生类,都属于动物这一大类派生出来的一小类)…我捏了哪些狗呢?我捏了拉布拉多、哈士奇、柯基(拉布拉多、哈士奇、柯基都是狗这个类的具体实例,都称之为狗这个类的对象)…创建完了动物,我便继续创建植物、人类…我甚至还创造了天气(类),我创造了下雨、打雷、大雾、烈日炎炎(这些都属于天气这个类的具体实例,即天气这个类的对象)…
很快一个世界变创建好了,我为什么会选择这个流程来创建世界呢?因为面向对象这个思路的优势在于,归纳总结事物的共同点,方便批量的生成有着共同点但也各不相同的事物,拿上述的例子来思考,我创建动物这个类是因为动物都有着吃、呼吸、运动等共同特征,我把这些共同点汇聚在一起,再创造动物岂不是很方便?于是我创建了狗、鸟、虎等动物派生类,它们的共同点就是吃、呼吸、运动等,只不过数值不同,狗吃50(满饱食度为100),鸟吃20,虎吃90,在编程世界里是不是可以用(eatAbility = 50、eatAbility = 20、eatAbility = 90)来表示呢?运动方式也不同,狗和虎是爬行,鸟是飞行,在编程世界里是不是可以用(action=‘move’、action=‘fly’)来表示呢?上述的eatAbility、action即为类中的属性,不仅如此,我们还可以继续派生,狗这个类可以派生出拉布拉多、哈士奇、柯基等更为具体的类,它们作为狗也都有着共同点(犬吠、吃骨头…)和不同点(性格不同、智商不同、长相体型不同…)
我们先创建一个简单的类,解释器中代码如下:
>>> class MyInfo:
... """自我介绍类"""
... name='Richie' # 属性
... age=22 # 属性
... def sayHello(self): # 方法
... print('Hello,' + self.name)
...
>>> mine = MyInfo() # 实例化类
>>> print(mine.name) # 访问类的属性
Richie
>>> print(mine.age) # 访问类的属性
22
>>> mine.sayHello() # 访问类的方法
Hello,Richie
类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例上,解释器中代码如下:
>>> class People:
... def __init__(self,name,age):
... self.name = name
... self.age = age
...
>>> me = People('Richie',22)
>>> print(me.name,me.age)
Richie 22
self代表类的实例,而非类,类的方法与普通的函数只有一个特别的区别:它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self
>>> class Test:
... def prt(self):
... print(self)
... print(self.__class__)
...
>>> t = Test()
>>> t.prt()
<__main__.Test object at 0x00000174163AF080>
<class '__main__.Test'>
从上面执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类
self 不是 python 关键字,我们把他换成别的名也是可以正常执行的,但是建议使用self来表示
在完善一下类,解释器中代码如下:
>>> class People:
... name='' # 基本属性
... age=0 # 基本属性
... __weight = 0 # 两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问
... def __init__(self,name,age,weight):
... self.name = name
... self.age = age
... self.__weight = weight
... def speak(self):
... print(self.name)
... print(self.age)
... print(self.__weight)
... self.__selfFunction()
... def __selfFunction(self): # 两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用
... print('我的私有属性')
...
>>> mine = People('Richie',22,65)
>>> mine.name
'Richie'
>>> mine.age
22
>>> mine.__weight # 私有属性,在类外部无法直接进行访问
AttributeError: 'People' object has no attribute '__weight'
>>> mine.speak()
Richie
22
65
我的私有属性
>>> mine.__selfFunction() # 报错
子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法,解释器中代码如下:
>>> class People:
... name=''
... age=0
... __weight = 0
... def __init__(self,name,age,weight):
... self.name = name
... self.age = age
... self.__weight = weight
... def speak(self):
... print(self.name)
... print(self.age)
... print(self.__weight)
...
>>> class Student(People): # 单继承示例
... score = 0
... def __init__(self,name,age,weight,score):
... People.__init__(self,name,age,weight) # 调用父类的构造函数
... self.score = score
... def speak(self): # 覆盖重写父类的方法
... print(self.name)
... print(self.age)
... print(self.score)
...
>>> s = Student('Richie',22,65,87)
>>> s.speak()
Richie
22
87
多继承,需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法,解释器中代码如下:
>>> class People:
... name=''
... age=0
... __weight = 0
... def __init__(self,name,age,weight):
... self.name = name
... self.age = age
... self.__weight = weight
... def speak(self):
... print(self.name)
... print(self.age)
... print(self.__weight)
...
>>> class Student(People):
... score = 0
... def __init__(self,name,age,weight,score):
... People.__init__(self,name,age,weight)
... self.score = score
... def speak(self):
... print(self.name)
... print(self.age)
... print(self.score)
...
>>> class Speaker():
... topic = ''
... name = ''
... def __init__(self,topic,name):
... self.name = name
... self.topic = topic
... def speak(self):
... print(self.name)
... print(self.topic)
...
>>> class Sample(Speaker,Student): # 多继承
... num = 0
... def __init__(self,name,age,weight,score,topic,num):
... student.__init__(self,name,age,weight,score)
... speaker.__init__(self,topic,name)
... self.num = num
...
>>> test = Sample("Richie",22,65,87,'Python',100)
>>> test.speak() # 方法名同,默认调用的是在括号中参数位置排前父类的方法,此处调用的是Speaker里的speak()方法
Richie
Python
方法重写,如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,解释器中代码如下:
>>> class Parent:
... def pFunction(self):
... print("Parent's function")
...
>>> class Child(Parent):
... def pFunction(self):
... print("Child's function")
...
>>> c = Child()
>>> c.pFunction() # 子类调用重写方法
Child's function
>>> super(Child,c).pFunction() # 用子类对象调用父类已被覆盖的方法
Parent's function