一 面向对象的由来
一、概述
二、详细发展历史
二 什么是面向对象设计以及为什么要有面向对象
三 类与对象
四 属性查找
五 绑定到对象方法的特殊之处
六 对象之间的交互
一 面向对象的由来
一、概述
1940年以前:面向机器
二 什么是面向对象设计以及为什么要有面向对象
就好比精心设计好一条流水线,是一种机械式的思维方式。
优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。
三 类与对象
类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体
那么问题来了,先有的一个个具体存在的对象(比如一个具体存在的人),还是先有的人类这个概念,这个问题需要分两种情况去看
在现实世界中:先有对象,再有类
世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念
也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在
在程序中:务必保证先定义类,后产生对象
这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类
不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象
1 #python为类内置的特殊属性 2 类名.__name__# 类的名字(字符串) 3 类名.__doc__# 类的文档字符串 4 类名.__base__# 类的第一个父类(在讲继承时会讲) 5 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 6 类名.__dict__# 类的字典属性 7 类名.__module__# 类定义所在的模块 8 类名.__class__# 实例对应的类(仅新式类中)
四 属性查找
类有两种属性:数据属性和函数属性
1. 类的数据属性是所有对象共享的
2. 类的函数属性是绑定给对象用的
#类的数据属性是所有对象共享的,id都一样 print(id(OldboyStudent.school)) print(id(s1.school)) print(id(s2.school)) print(id(s3.school)) ''' 4377347328 4377347328 ''' #类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样 #ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准 print(Student.learn) print(s1.learn) print(s2.learn) print(s3.learn) ''' <function Student.learn at 0x1021329d8> <bound method Student.learn of <__main__.Student object at 0x1021466d8>> <bound method Student.learn of <__main__.Student object at 0x102146710>> <bound method Student.learn of <__main__.Student object at 0x102146748>> '''
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
五 绑定到对象方法的特殊之处
1 #改写 2 class Student: 3 school='SkyEdu' 4 def __init__(self,name,age,sex): 5 self.name=name 6 self.age=age 7 self.sex=sex 8 def learn(self): 9 print('%s is learning' %self.name) #新增self.name 10 11 def eat(self): 12 print('%s is eating' %self.name) 13 14 def sleep(self): 15 print('%s is sleeping' %self.name) 16 17 18 s1=Student('jack','男',18) 19 s2=Student('lucy','女',38) 20 s3=Student('lee','男',78)
类中定义的函数(没有被任何装饰器装饰的)是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数
类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法
强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)
注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。
类即类型
提示:python的class术语与c++有一定区别,与 Modula-3更像。
python中一切皆为对象,且python3中类与类型是一个概念,类型就是类
1 #类型dict就是类dict 2 >>> list 3 <class 'list'> 4 5 #实例化的到3个对象l1,l2,l3 6 >>> l1=list() 7 >>> l2=list() 8 >>> l3=list() 9 10 #三个对象都有绑定方法append,是相同的功能,但内存地址不同 11 >>> l1.append 12 <built-in method append of list object at 0x10b482b48> 13 >>> l2.append 14 <built-in method append of list object at 0x10b482b88> 15 >>> l3.append 16 <built-in method append of list object at 0x10b482bc8> 17 18 #操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3 19 >>> l1.append(3) 20 >>> l1 21 [3] 22 >>> l2 23 [] 24 >>> l3 25 [] 26 #调用类list.append(l3,111)等同于l3.append(111) 27 >>> list.append(l3,111) #l3.append(111) 28 >>> l3 29 [111]
六 对象之间的交互
1 class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄; 2 camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia; 3 def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...; 4 self.nickname=nickname #为自己的盖伦起个别名; 5 self.aggressivity=aggressivity #英雄都有自己的攻击力; 6 self.life_value=life_value #英雄都有自己的生命值; 7 def attack(self,enemy): #普通攻击技能,enemy是敌人; 8 enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。
我们可以仿照garen类再创建一个Riven类
1 class Riven: 2 camp='Noxus' #所有玩家的英雄(锐雯)的阵营都是Noxus; 3 def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54; 4 self.nickname=nickname #为自己的锐雯起个别名; 5 self.aggressivity=aggressivity #英雄都有自己的攻击力; 6 self.life_value=life_value #英雄都有自己的生命值; 7 def attack(self,enemy): #普通攻击技能,enemy是敌人; 8 enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。
实例出俩英雄
1 >>> g1=Garen('草丛伦') 2 >>> r1=Riven('锐雯雯')
交互:锐雯雯攻击草丛伦,反之一样
1 >>> g1.life_value 2 455 3 >>> r1.attack(g1) 4 >>> g1.life_value 5 401