python的面向对象
一.面向对象编程和面向过程
• 面向对象编程——Object Oriented Programming,简称 OOP,把
对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
• 面向过程把函数继续切分为子函数,来降低系统的复杂度。
二.类
• 类: 在 Python 中,所有数据类型都可以视为对象,当然也可以自
定义对象。自定义的对象数据类型就是面向对象中的类(Class)。
# 类: Cat, Dog, Animals
# 对象:fentiao, dahuang
# 属性: 这个对象的特征:(name, age, weight)
# 方法:这个对象可以做什么(eat, drink, eatMouse)
1.类的创建:(基类)和子类(派生类)
# 创建类:
class Cat(object): #所有类的父类均可为object
#构造方法,当时示例化对象时会自动执行;
def __init__(self,name,age,weight):
#self实质是一个对象,self --- linux
print("self:",self)
# attribute:属性,把属性和对象绑定在一起,linux.name可以获取名字
self.name = name
self.age = age
self.weight = weight
#实例化对象:
juzi = Cat('juzi',18,90)
print(juzi.name) #通过对象名获得属性值
print(juzi.age)
print(juzi.weight)
执行结果:
2.封装:
数据封装:
• 数据和逻辑被“封装”起来了,调用很容易,但却不用知道内部实现的细节。
• 封装的另一个好处是可以给类增加新的方法。
class Cat(object):
def __init__(self, name, age, weight):
# 封装: 将属性均绑定在self变量上;
self.name = name
self.age = age
self.weight = weight
# 类里面的函数第一个参数时self,
并且pyhton解释器自动将对象传给self变量;
def eat(self): # java: this
self.weight += 2
print("%s is eating, now weight is %s" %(self.name, self.weight))
# 如何调用封装的数据?
# - fentiao.name # 直接调用
# - self.name # 通过self间接调用
3.继承和多态:
# 父类和子类, 基类和派生类
class Animais(object):
def __init__(self,name,age):
#属性:
self.name = name
self.age = age
#方法:
def eat(self):
print("%s is eating......" %(self.name))
#Cat的父类是Animais
class Cat(Animais):
def __init__(self,name,age,fishCount):
# self.name = name
# self.age = age
# 去执行父类的构造函数;
Animais.__init__(self,name,age)
# 执行Cat父类的构造函数, 不包含父类的任何信息;
# 如果Cat的父类变化, 无需进入类里面修改;
super(Cat,self).__init__(name,age)
self.fishCount = fishCount
# Cat没有__init__函数, 则调用父类的构造函数;如果父类没有, 则找父类的父类,
# 依次类推, 一直没有, 则不执行;
# 多态: 当父类和子类有同一方法时, 优先执行子类的方法;
def eat(self):
super(Cat,self).eat()
self.fishCount -= 2
print("cat %s ia eating, now have fish %s" %(self.name,self.fishCount))
#Dog类的父类是Animais;
class Dog(Animais):
pass
a = Animais('猫',10)
a.eat()
print(a.name)
print(a.age)
juzi = Cat('juzi',10,20)
juzi.eat()
# 父类没有drink方法, 则不能执行;
# juzi.drink()
4.新式类和经典类
• pyhton3:都是新式类
• python2:新式类和经典类
• 新式类:广度优先 A -> B,C -> (B->D)|(C->D)
• 经典类:深度优先 A -> B -> D -> C -> D
class D:
# pass
def test(self):
print("D test")
class C(D):
# pass
def test(self):
print("C test")
class B(D): ##父类B没有定义,依次查找上一级
pass
# def test(self):
# print("B test")
class A(B,C): ##A实例化的时候,调用函数test时,查找父类的函数
pass
# def test(self):
# print("A test")
a_t = A() ##python2中,输出:D test
a_t.test() ##python3中,输出:C test
三.魔术方法
1.常用魔术方法
def _init_(self): 封装
def _str_(self): 字符串显示,自动调用
def _getitem_(self, item): 实例化对象可以索引和切片
def _setitem_(self, key, value): 实例化对象可以通过索引和切片修改值
def _delitem_(self, key): 实例化对象可以通过索引和切片删除值
class Student(object):
#封装:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other): #等于
# stu1 == stu2 (other=stu2) other是个对象
self.stu1_avg = sum(self.score)/len(self.score)
self.stu2_avg = sum(other.score)/len(other.score)
return self.stu1_avg == self.stu2_avg
def __lt__(self, other): #小于
return self.stu1_avg < self.stu2_avg
def __gt__(self, other): #大于
return not self.__lt__(other)
def __ne__(self, other): #不等于
return not self.__eq__(other)
def __getitem__(self, index): # s[0] index=0
# 当类里面有__getitem__魔术方法时, 该类实例化的对象是可以索引和切片的;
return self.score[index]
def __setitem__(self, index, value): # s[0] = 85 # index=0, value=85
# 当类里面有__setitem__魔术方法时, 该类实例化的对象是可以通过索引和切片修改值的;
self.score[index] = value
def __delitem__(self, key): # del s[0]
# 当类里面有__delitem__魔术方法时, 该类实例化的对象是可以删除指定索引值或者切片值;
del self.score[key]
2.slice内置方法
>>> a = slice(1,10,2)
>>> List = list(range(10))
>>> List
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> List[a] #类似与切片
[1, 3, 5, 7, 9]
>>> List[1:10:2]
[1, 3, 5, 7, 9]
示例:图书管理系统:
class Book(object):
#构造函数,在实例化对象时自动执行;
def __init__(self,name,author,state,BookIndex):
# oop的特性:封装
self.name = name
self.author = author
# 0: 未借出, 1代表借出
self.state = state
self.BookIndex = BookIndex
def __str__(self):
# 实质是对象的字符串显示;
# 当str(对象名)会自动调用;
# print(对象名)也会自动调用
if self.state == 0:
state = "未借出"
if self.state == 1:
state = "借出"
return "Book(%s, %s, %s, %s)" % (
self.name, self.author, state, self.BookIndex)
class BookManage(object):
booklist = []
#初始化图书信息
def initBook(self):
self.booklist.append(Book('python','Guido',0,'PY001'))
self.booklist.append(Book('Java','Guido',0,'JA001'))
self.booklist.append(Book('Linux','Linus',0,'LI001'))
#定义menu函数,进行循环
def menu(self):
info = """
BookManage System
1. add
2. borrow
3. check
4. view
5. delete
6. exit
Please input your choice:"""
while True: #循环,根据用户的选择执行不同操作
choice = input(info)
if choice == '1':
self.addBook()
elif choice == '2':
self.borrowBook()
elif choice == '3':
self.usercheck()
elif choice == '4':
self.viewBook()
elif choice == '5':
self.deleteBook()
elif choice == '6':
exit(0)
def addBook(self): ##添加图书信息
"""添加书籍操作"""
print("添加书籍".count(30,'*'))
name = input("BookName:")
author = input("BookAuthor:")
bookIndex = input("BookIndex:")
# 将Book实例化的对象添加到列表中;
# 新加的书籍肯定是未借出;
self.booklist.append(Book(name,author,0,bookIndex))
print("添加书籍%s成功!" %(name))
def borrowbook(self):
"""借阅书籍"""
# 1. 查看书籍是否存在?
# 2. 修改书籍状态;
print("借阅书籍".center(30,'*'))
name = input("借阅书籍名称:")
# 如果找到, 返回书籍对象对象里面包含书籍的所有属性;
# 如果没有找到返回None;
BookRes = self.checkBook(name)
if BookRes:
if BookRes.state == 0:
#修改书籍状态:
BookRes.state = 1
print("借阅%s成功!" %(name))
else:
print("书籍%s已借出" %(name))
else:
print("书籍%s不存在" %(name))
def checkbook(self,name):
"""查询书籍信息"""
#book是Book的对象,book.name ,book.author...
for book in self.booklist:
if name == book.name:
return book
#依次找所有的书籍信息,没有一个书名为name,那么未找到;
else:
return None
def userCheck(self):
print("查询书籍信息".center(30,'*'))
name =input("查询书籍名称:")
BookRes = self.checkbook(name)
if BookRes:
print("找到书籍%s" %(name))
print(BookRes)
else:
print("未找到书籍%s" %(name))
def viewBook(self):
"""查询书籍信息"""
print("查询书籍信息".center(30,'*'))
# self.bookList是一个列表, 可以for循环;
# 列表里面的每一个元素是Book对象;
for book in self.booklist:
print(book)
def deleteBook(self):
"""删除书籍信息"""
name = input("删除书籍名称:")
BookRes = self.checkBook(name)
if BookRes:
print("%s书籍删除成功!" %(name))
else:
print("%s书籍未找到!" %(name))
def main(): #定义main函数
bm = BookManage() #实例化
bm.initBook() #初始化
print("初始化书籍信息系统成功")
bm.menu()
# 判断的是脚本内容数否为被导入的模块:
if __name__ == '__main__':
main()
四.类操作
1.类属性
1、私有属性:只能在类中使用的属性(双下划线__)
self.__state = state
2、私有方法:只能在类中使用的方法(双下划线__)
def get__state(self):
示例:
class Book(object):
# 构造函数,在实例化对象时自动执行;
def __init__(self,name,author,state,BookIndex):
# oop的特性:封装
self.name = name
self.author = author
# 0: 未借出, 1代表借出
# 私有属性: 只能在这个类里面使用的属性;
self.__state = state
self.BookIndex = BookIndex
#私有方法,类外部不能调用
def get__state(self):
if self.__state == 0:
return '未借出'
if self.__state == 1:
return '借出'
#私有方法,类外部不能调用
def set__state(self,value):
if value in [0,1]:
self.__state = value
return True
else: #raise:抛出异常
raise Exception("状态值只能在0或1之间")
book1 = Book('linux','linux',0,'LI4545') #实例化对象
# book.__sate #会报错,不能调用state
print(book1.get__state()) #调用函数
# book1.set__state(3) ##3不符合state要求,会抛出异常
print(book1.get__state())
3.类属性装饰器 @property
class Book(object):
def __init__(self,name,author,state,index):
self.name = name
self.author = author
self.state = state
self.index = index
@property #代表state不是方法,是一个属性值,
def state(self):
if self.__state == 0:
return "未借出"
if self.__state == 1:
return "借出"
@state.setter #book.state = value 赋值或者修改
def state(self,value):
if value in [0,1]:
self.__state = value
return True
else: #捕获异常
raise Exception("状态值只能在0或1之间")
#实例化对象
book = Book('linux','linux',0,'LI6572')
#类属性装饰器装饰后,可直接调用,并对state做了限制
print(book.state)
book.state = 1
print(book.state)