1. 面向过程VS面向对象
(1)面向过程
核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
(2)面向对象
核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
2. 相关名词概念
(1)类
类:具有相同特征的一类事物(人、狗、老虎)
(2)对象(实例)
对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
(3)实例化
实例化:类——>对象的过程(这在生活中表现的不明显,我们在后面再慢慢解释)
3. 类的相关知识
(1)类的定义
class Person: #定义一个类:Person role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
(2)类的作用
<1>属性引用
属性引用(类名.属性)
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
<2>实例化
语法:对象名 = 类名(参数)
类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
实例化的过程就是类——>对象的过程
原本我们只有一个Person类,在这个过程中,产生了一个egg对象,有自己具体的名字、攻击力和生命值。
egg = Person('egon') #类名()就等于在执行Person.__init__() #执行完__init__()就会返回一个对象。这个对象类似一个字典,存着属于这个人本身的一些属性和方法。
<3> 查看属性&调用方法
print(egg.name) #查看属性直接 对象名.属性名 print(egg.walk()) #调用方法,对象名.方法名()
<4> 关于self
self:在实例化时自动将对象/实例本身传给__init__的第一个参数,一般不做修改。
(3)类属性的补充
<1> 我们定义的类的属性到底存到哪里了?
有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
<2> 特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
4. 对象的相关知识
对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种作用:属性引用
动态属性:方法调用
print(egg.attack)
定义及调用的固定模式
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可 小结
5. 对象之间的交互
实例化一只实实在在的二哈
ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2
交互 egon打ha2一下
print(ha2.life_value) #看看ha2的生命值 egg.attack(ha2) #egg打了ha2一下 print(ha2.life_value) #ha2掉了10点血
6. 类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
(1)类的两种属性
静态属性和动态属性
<1> 静态属性
直接在类中定义的变量——共享给所有对象的
<2> 动态属性
定义在类中的方法——绑定到所有对象的
class Course: language = 'Chinese' # 静态属性 def __init__(self,teacher,name,period,price): self.teacher = teacher, self.name = name, self.period = period, self.price = price def func(self): print('pass') python = Course('egon','python','6 months',20000) linux = Course('eva','linux','6 months',20000)
print(python.language) # English 类中的静态变量可以被对象调用 print(Course.language) # English 类中的静态变量可以被类调用 linux.func() # pass 类中的动态变量可以被对象调用 Course.func(linux) # pass 类中的动态变量可以被类调用(需要传参)
Course.language = 'English' # 静态属性修改 print(Course.language) # English 修改成功 # Course.__dict__['language'] = 'Chinese' # 不可以这么修改 # print(Course.language) # 报错
(2)静态变量的修改
<1> 类修改静态变量:
language = 'Chinese' 字符串【不可变数据类型】
<2> 对象修改静态属性
对于【不可变数据类型】来说
类变量最好用类名操作(如上例子)
因为用对象修改不是真正的修改,而是在对象自己的空间中创建新的同名属性
只有创建的同名属性删除后,才可以调用类中的静态属性
print(python.language) # English print(linux.language) # English python.language = 'Chinese' # 不能修改静态变量language,而是在自己的空间中创建了language的 print(python.language) # Chinese print(python.__dict__) # {'teacher': ('egon',), ... , 'price': 20000, 'language': 'Chinese'} print(linux.language) # English print(linux.__dict__) # {'teacher': ('eva',), ... , 'price': 20000} del python.language # 自己创建的language删除之后,才能使用类中的静态变量 print(python.language) # English
对于【可变数据类型】来说
类中的静态变量:language = ['Chinese'] 列表【可变数据类型】
<1> 对象名的修改是共享的
python.language[0] = 'English' print(python.language) # ['English'] print(python.__dict__) # {'teacher': ('egon',), ... , 'price': 20000} print(linux.language) # ['English'] print(linux.__dict__) # {'teacher': ('eva',), ... , 'price': 20000}
<2> 对象名的重新赋值是独立的
python.language = 'English' print(python.language) # English python.language = ['English'] print(python.language) # ['English'] print(python.__dict__) # {'teacher': ('egon',), ... ,'price': 20000, 'language': 'English'} print(linux.language) # ['Chinese'] print(linux.__dict__) # {'teacher': ('eva',), ... , 'price': 20000}
(3)应用举例
需求:创建一个类,每实例化一个对象就记录下来最终所有的对象共享这个数据
class Person: count = 0 def __init__(self,name): self.name = name Person.count += 1 n1 = Person('gxx') print(n1.count) # 1 n2 = Person('xcc') print(n1.count) # 2 print(n2.count) # 2 n3 = Person('xcc') print(n1.count) # 3 print(n2.count) # 3 print(n3.count) # 3
7. 认识绑定方法
# 函数 func def func(): pass print(func) # <function func at 0x000001FA4DC7F0D0> # 类中的方法 Foo.func class Foo: def func(self): print('func类里') f1 = Foo() print(Foo.func) # <function Foo.func at 0x000001FA4DC7F2F0> # 对象调用方法的时候才有绑定方法 print(f1) # f1 <__main__.Foo object at 0x000001E57FE9E358> print(f1.func) # f1对象的绑定方法<bound method Foo.func of <__main__.Foo object at 0x000001FA4DC7E358>> # 把对象f1以self的形式传到方法中
8. 组合
组合:(面向对象的一种用法)
一个对象的属性值是另一个类的对象
class Dog: def __init__(self,name,aggr,blood,kind): self.name = name self.aggr = aggr self.blood = blood self.kind = kind def bite(self,person): person.blood -= self.aggr class Person: def __init__(self,name,aggr,blood,sex): self.name = name self.aggr = aggr self.blood = blood self.sex = sex self.money = 0 def attack(self,dog): dog.blood -= self.aggr def get_weapon(self,weapon): if self.money >= weapon.price: self.money -= weapon.price self.weapon = weapon self.aggr += weapon.aggr else: print('余额不足,请充值') class Weapon: def __init__(self,name,aggr,njd,price): self.name = name self.aggr = aggr self.njd = njd self.price = price alex = Person('alex',1,10,'m') jin = Dog('金老板',1000,500,'td') w = Weapon('打狗棒',100,3,998) alex.attack(jin) # alex打了一下jin print(jin.blood) # 499 alex.money += 1000 alex.get_weapon(w) print(alex.weapon) # <__main__.Weapon object at 0x000001C38FC64B70> print(jin.blood) # 499 alex.attack(jin) # alex用武器打了一下jin print(jin.blood) # 398
from math import pi class Circle: def __init__(self,r): self.r = r def zc(self): return 2*pi*self.r def mj(self): return pi*self.r*self.r class Ring: def __init__(self,outside_r,inside_r): self.outside_c = Circle(outside_r) self.inside_c = Circle(inside_r) def area(self): return self.outside_c.mj() - self.inside_c.mj() def perimeter(self): return self.outside_c.zc() + self.inside_c.zc() ring = Ring(20,10) print(ring.area()) print(ring.perimeter())
# 用组合实现:创建老师类,生日类,课程类,老师有生日,有课程信息 class Course: def __init__(self,cname,price,time): self.cname = cname self.price = price self.time = time class Birthday: def __init__(self,year,month,day): self.year = year self.month = month self.day = day class Teacher: def __init__(self,tname,sex,age,courseinfo,birth): self.tname = tname self.sex = sex self.age = age self.birth = birth self.course = courseinfo b = Birthday(1996,7,18) c = Course('Linux',2000,'2 days') t = Teacher('xc','f',22,c,b) print('老师姓名:' + t.tname) # 老师姓名:xc print(t.birth.year) # 1996 print('课程价格:' + str(t.course.price)) # 课程价格:2000
借鉴:http://www.cnblogs.com/Eva-J/articles/7293890.html#_label1