01-10. 模块的使用与面向对象思想简介07-08
1 概述
面向过程
- 自上而下顺序执行,逐步求精;
- 其程序结构是按功能划分为若干个基本模块,这些模块形成一个树状结构;
- 各模块之间的关系尽可能简单,在功能上相对独立;
- 每一模块内部均是由顺序、选择和循环三种基本结构组成;
- 其模块化实现的具体方法是使用子程序。
程序流程在写程序时就已决定。
面向对象
- 把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象;
- 对同类对象抽象出其共性,形成类;
- 类中的大多数数据,只能用本类的方法进行处理;
- 类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
程序流程由用户在使用中决定。
2 类
01-11. 面向对象思想的编程01
设计类
- 类名:见名知意,首字母大写,其他遵循驼峰原则;
- 属性:见名知意,遵循驼峰原则;
- 行为(方法/功能):见名知意,遵循驼峰原则。
例子:
类名:Wife
属性:sex age height weight faceValue
行为:做饭 洗衣服 拖地 揉肩 捶腿
创建类
类是一种数据类型,本身并不占内存空间,跟所学过的number,string,boolean等类似。用类创建实例化对象(变量),对象占内存空间。
格式:
class 类名(父类列表):
属性
行为
# object:基类,超类,所有类的父类,一般没有合适的父类就写objectclass Person(object):#定义属性(定义变量)name = ""age = 0height = 0weight = 0#定义方法(定义函数)#注意:方法的参数必须以self当第一个参数#self代表类的实例(某个对象)def run(self):print("run")def eat(self, food):print("eat" + food)
实例化对象
格式:
对象名 = 类名(参数列表)
注意:没有参数,小括号也不能省略
class Person(object):name = ""age = 0height = 0weight = 0def run(self):print("run")def eat(self, food):print("eat" + food)def openDoor(self):print("我已经打开了冰箱门")def fillEle(self):print("我已经把大象装进冰箱了")def closeDoor(self):print("我已经关闭了冰箱门")#实例化一个对象per1 = Person()print(per1)print(type(per1))print(id(per1))per2 = Person()print(per2)print(type(per2))print(id(per2))
访问对象的方法和属性
01-11. 面向对象思想的编程02
class Person(object):name = "stu"age = 10height = 160weight = 90def run(self):print("run")def eat(self, food):print("eat " + food)def openDoor(self):print("我已经打开了冰箱门")def fillEle(self):print("我已经把大象装进冰箱了")def closeDoor(self):print("我已经关闭了冰箱门")per = Person()'''访问属性格式:对象名.属性名赋值:对象名.属性名 = 新值'''per.name = "tom"per.age = 18per.height = 160per.weight = 80print(per.name, per.age, per.height, per.weight)'''访问方法格式:对象名.方法名(参数列表)'''per.openDoor()per.fillEle()per.closeDoor()per.eat("apple")
3 类方法
构造函数
01-11. 面向对象思想的编程02
init() 在使用类创建对象的时候自动调用
注意:如果不显示的写出构造函数,默认会自动添加一个空的构造函数
class Person(object):#name = "stu"#age = 10#height = 160#weight = 90def run(self):print("run")def eat(self, food):print("eat " + food)def __init__(self, name, age, height, weight):#print(name, age, height, weight)#定义属性self.name = nameself.age = ageself.height = heightself.weight = weightper = Person("hanmeimei", 20, 170, 55)print(per.name, per.age)per2 = Person("lilei", 21, 175, 70)print(per2.name, per2.age)per.run()
self
01-11. 面向对象思想的编程03
self代表类的实例,而非类。哪个对象调用方法,那么该方法中的self就代表那个对象。
self.class 代表类名_
class Person(object):def run(self):print("run")print(self.__class__)p = self.__class__("tt", 30, 10, 30)print(p)def eat(self, food):print("eat " + food)def say(self):print("Hello! my name is %s, I am %d years old" % (self.name, self.age))#self不是关键字,换成其他的标识符也是可以的,但是帅的人都是用selfdef play(a):print("play " + a.name)def __init__(self, name, age, height, weight):self.name = nameself.age = ageself.height = heightself.weight = weightper1 = Person("tom", 20, 160, 80)per1.say()#-->Hello! my name is tom, I am 20 years oldper2 = Person("hanmeimei", 21, 160, 80)per2.say()#-->Hello! my name is hanmeimei, I am 21 years oldper1.play()#-->play tomper1.run()#-->run#--><class '__main__.Person'>#--><__main__.Person object at 0x00000000025E3100>
析构函数
01-11. 面向对象思想的编程03
del() 释放对象是自动调用。默认系统自动释放对象,程序不结束不释放对象。程序不结束,即使写了del函数也不会执行,但是使用了del命令后,del函数就会执行。
class Person(object):def run(self):print("run")def eat(self, food):print("eat " + food)def __init__(self, name, age, height, weight):self.name = nameself.age = ageself.height = heightself.weight = weightdef __del__(self):print("这里是析构函数")per = Person("hanmeimei", 20, 170, 55)#释放对象per.eat("apple")#-->eat apple#-->这里是析构函数
上述代码添加以下代码后,析构函数不执行。
while 1:pass
在函数里定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费。
class Person(object):def run(self):print("run")def eat(self, food):print("eat " + food)def __init__(self, name, age, height, weight):self.name = nameself.age = ageself.height = heightself.weight = weightdef __del__(self):print("这里是析构函数")per = Person("hanmeimei", 20, 170, 55)#释放对象del per#-->这里是析构函数#对象释放以后就不能再访问了#print(per.age)#在函数里定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费def func():per2 = Person("aa", 1, 1, 1)func()#-->这里是析构函数while 1:pass
重写repr与str函数
01-11. 面向对象思想的编程04
将函数重写定义写一遍。
str():在调用print打印对象时自动调用,是给用户用的,是一个描述对象的方法。
repr():是给机器用的,在Python解释器里面直接敲对象名在回车后调用的方法。
注意:在没有str()时,且有repr(),str = repr
class Person(object):def __init__(self, name, age, height, weight):self.name = nameself.age = ageself.height = heightself.weight = weightdef __str__(self):return "%s-%d-%d-%d" % (self.name, self.age, self.height, self.weight)per = Person("hanmeimei", 20, 170, 55)print(per)#-->hanmeimei-20-170-55
使用str优点是,当一个对象的属性值很多,并且都需要打印,重写了str方法后,简化了代码。
访问限制
01-11. 面向对象思想的编程05
如果要让内部属性不被外部直接访问,在属性前加两个下划线(__),在Python中如果在属性前加两个下划线,那么这个属性就变成了私有属性。
class Person(object):def run(self):print("run")def showMoney(self):print(self.__money)def showWeight(self):print(self.weight)def __init__(self, name, age, height, weight, money):self.name = nameself.__age__ = ageself._height = heightself.weight = weightself.__money = money#_Person__moneyper = Person("hanmeimei", 20, 170, 55, 100000)#此处虽然对__money进行了赋值,这其实是创建了一个新的参数,与内部的私有属性__money不再一致per.__money=0print(per.__money)#-->0per.showMoney()#-->100000#此处weight是内部属性,对其进行了内部修改per.weight=180print(per.weight)#-->180per.showWeight()#-->180
可以通过内部的方法,去修改私有属性。
class Person(object):def run(self):print(self.__money)print("run")def __init__(self, name, age, height, weight, money):self.name = nameself.__age__ = ageself._height = heightself.weight = weightself.__money = money#_Person__money#通过自定义的方法实现对私有属性的赋值与取值def setMoney(self, money):#数据的过滤if money < 0:money = 0self.__money = moneydef getMoney(self):return self.__moneyper = Person("hanmeimei", 20, 170, 55, 100000)per.setMoney(10)print(per.getMoney())#-->10#不能直接访问per.__money,是因为Python解释器把__money变成了_Person__money,仍然可以用_Person__money去访问,但是强烈建议不要这么干(帅的人都不这么干),不同的解释器可能存在解释的变量名不一致per._Person__money = 1print(per.getMoney())#-->1#在Python中 __XXX__ 属于特殊变量,可以直接访问print(per.__age__)#-->20#在Python中 _XXX 变量,这样的实例变量外部是可以访问的,但是,按照约定的规则,当我们看到这样的变量时,意思是“虽然我可以被访问,但是请把我视为私有变量,不要直接访问我”print(per._height)#-->170
作业
人开枪射击子弹
01-11. 面向对象思想的编程06-07
#bulletbox.pyclass BulletBox(object):def __init__(self, count):self.bulletCount = count
#gun.pyclass Gun(object):def __init__(self, bulletBox):self.bulletBox = bulletBoxdef shoot(self):if self.bulletBox.bulletCount == 0:print("没有子弹了")else:self.bulletBox.bulletCount -= 1print("剩余子弹:%d发" % (self.bulletBox.bulletCount))
#person.pyclass Person(object):def __init__(self, gun):self.gun = gundef fire(self):self.gun.shoot()def fillBullet(self, count):self.gun.bulletBox.bulletCount = count
#人开枪射击子弹.pyfrom person import Personfrom gun import Gunfrom bulletbox import BulletBox'''人类名:Person属性:gun行为:fire枪类名:Gun属性:bulletBox行为:shoot弹夹类名:BulletBox属性:bulletCount行为:'''#弹夹bulletBox = BulletBox(5)#枪gun = Gun(bulletBox)#人per = Person(gun)per.fire()per.fire()per.fire()per.fire()per.fire()per.fire()per.fire()per.fillBullet(2)per.fire()per.fire()per.fire()
4 类的继承
01-11. 面向对象思想的编程07
object类是所有类的父类,还可以称为基类或超类。
继承:有两个类,A类和B类,当我们说A类继承自B类的时候,那么A 类就拥有了 B类中的所有的属性和方法。
注意:继承者称为子类,被继承自继承者称为父类。
继承的作用:
- 简化了代码,减少冗余;
- 提高了代码的健壮性;
- 提高了代码的安全性;
- 是多态的前提。
缺点:耦合与内聚是描述类与类之间的关系的。耦合性越低,内聚性越高,代码越好。
建议Python文件名首字母小写,类名首字母大写。
单继承的实现
01-11. 面向对象思想的编程08
#person.pyclass Person(object):def __init__(self, name, age, money):self.name = nameself.age = ageself.__money = moneydef setMoney(self, money):self.__money = moneydef getMoney(self):return self.__moneydef run(self):print("run")def eat(self, food):print("eat " + food)
#student.pyfrom person import Personclass Student(Person):def __init__(self, name, age, money, stuId):#调用父类中的__init__super(Student, self).__init__(name, age, money)#子类可以有一些自己独有的属性self.stuId = stuIddef stuFunc(self):print(self.__money)
#单继承的实现.pyfrom person import Personfrom student import Studentper = Person("aa", 1, 2)stu = Student("tom", 18, 12345, 110)print(stu.name, stu.age)stu.run()print(stu.stuId)#print(stu.__money)私有属性print(stu.getMoney()) #通过继承过来的共有方法访问私有属性#stu.stuFunc()print(per.getMoney())
多继承的实现
01-12. 面向对象提升与收发邮件01
#Father.pyclass Father(object):def __init__(self, money):self.money = moneydef play(self):print("play")def func(self):print("func1")
#Mother.pyclass Mother(object):def __init__(self, faceValue):self.faceValue = faceValuedef eat(self):print("eat")def func(self):print("func2")
#Child.pyfrom Father import Fatherfrom Mother import Motherclass Child(Father, Mother):def __init__(self, money, faceValue):#写法Father.__init__(self, money)Mother.__init__(self, faceValue)
#多继承的实现.pyfrom Child import Childdef main():c = Child(300, 100)print(c.money, c.faceValue)c.play()c.eat()#注意:父类中方法名相同,默认调用的是在括号中排前面的父类中的方法c.func()if __name__ == "__main__":main()
5 多态
01-12. 面向对象提升与收发邮件02
6 对象属性与类属性
01-12. 面向对象提升与收发邮件03
以后千万不要将对象属性与类属性重名,因为对象属性会屏蔽掉类属性。但是当删除对象属性后,再使用又能使用类属性了。
class Person(object):# 这里的属性实际上属于类属性(用类名来调用)name = "person"def __init__(self, name):pass#对象属性self.name = nameprint(Person.name)per = Person("tom")#对象属性的优先级高于类属性print(per.name)#动态的给对象添加对象属性per.age = 18 #只针对于当前对象生效,对于类创建的其他对象没有作用print(Person.name)per2 = Person("lilei")#print(per2.age) #没有age属性#删除对象中的name属性,再调用时,会使用到同名的类属性del per.nameprint(per.name)
动态添加属性与方法
01-12. 面向对象提升与收发邮件04
动态添加属性,可以直接添加;动态添加方法,需要引入from types import MethodType,并使用MethodType。
from types import MethodType#创建一个空类class Person(object):passper = Person()#动态添加属性,这体现了动态语言的特点(灵活)per.name = "tom"#动态添加方法'''def say(self):print("my name is " + self.name)per.speak = sayper.speak(per)'''def say(self):print("my name is " + self.name)per.speak = MethodType(say, per)per.speak()
以上方法,可以给实例添加任意属性及方法。如果只允许给对象添加特定属性,如name,age,height,weight等属性,可以定义类的时候,定义一个特殊的属性(slots),限制动态添加的属性。
class Person(object):__slots__ = ("name", "age", "speak")per = Person()per.name = "tom"# 添加非限定内的属性会报错。per.height = 170print(per.height)
运行时会提示“AttributeError: ‘Person’ object has no attribute ‘height’”错误。
定义访问受限属性方法二:@property
01-12. 面向对象提升与收发邮件05
除使用set和get方法对属性进行限制外,还可以使用@property对属性进行限制。@property可以对受限制访问的属性使用点语法(如per.age来访问实例的年龄__age)。
class Person(object):def __init__(self, name, age):#属性直接对外暴露#self.age = age#限制访问self.__age = ageself.__name = name'''def getAge(self):return self.__agedef setAge(self, age):if age < 0:age = 0self.__age = age'''#方法名为受限制的变量去掉双下划綫@propertydef age(self):return self.__age@age.setter #去掉下划线.setterdef age(self, age):if age < 0:age = 0self.__age = ageper = Person(18)per.age = -100 #相当于调用setAageprint(per.age) #相当于调用getAge
7 运算符重载

class Person(object):def __init__(self, num):self.num = num#运算符重载def __add__(self, other):return Person(self.num + other.num)def __str__(self):return "num = " + str(self.num)per1 = Person(1)per2 = Person(2)print(per1 + per2)#per1 + per2 ==== per1.__add__(per2)print(per1)print(per2)
8 银行系统实战
01-13. tkinter与银行系统实战01-04
代码略。
