day22 python面向对象 封装/继承/多态
一.面向对象
1.函数式编程和面向对象的对比
1.1.对比一: 请开发一个消息提醒的功能(邮件/短信/微信)
1.1.1.函数式编程: 实现
def email(em,text):
'''
send email
:return:
'''
print('send email')
def msg(tel,text):
'''
send msg
:return:
'''
print('send msg')
def wechat(num,text):
'''
send wechat
:return:
'''
print('send wechat')
#编写功能:假设用户购买课程, 然后给bajie发送提醒, 三个都发
buy = 1
if buy:
msg('10086','bajie buy a class')
email('[email protected]','bajie buy a class')
wechat('3456654','bajie buy a class')
1.1.2.面向对象: 来实现上面的功能
class Message:
def email(self,em, text):
'''
send email
:return:
'''
print('send email')
def msg(self,tel, text):
'''
send msg
:return:
'''
print('send msg')
def wechat(self,num, text):
'''
send wechat
:return:
'''
print('send wechat')
buy = 1
if buy:
obj = Message()
obj.msg('10086', 'bajie buy a class') #少传了一个参数? 面向对象内部会把obj传给self
obj.email('[email protected]', 'bajie buy a class')
obj.wechat('3456654', 'bajie buy a class')
1.1.3.对比:
函数时:定义简单/调用简单
面向对象:定义复杂/调用复杂, 有一个好处是做了一个归类
1.1.4.总结:
1.函数式编程可能会比面向对象好
2.python中支持两种编程方式
3.面向对象方式的格式:
定义:
class 类名: #定义了一个类
def 函数名(self): #至少一个参数, self这个名字就是这个,比较专业 #在类中编写了一个方法
pass
调用:
obj = 类名() #创建了一个对象或者叫实例化了一个对象
obj.函数名() #传参否: 要看定义的时候是否写了参数 #通过对象调用其中的方法
示例:
class Account:
def login(self):
user = input('user: ')
password = input('password: ')
if user == 'bajie' and password == 'bajie123':
print('successful')
else:
print('incorrect')
obj = Account()
obj.login()
1.2.对比二: 请帮我打印
bajie/20/男/上山去砍柴
bajie/20/男/开车去东北
bajie/20/男/喜欢大宝剑
1.2.1.函数式编程
def kc(name,age,gender):
data = "%s,gender%s,is%syears old,love kc" % (name,gender,age)
print(data)
def db(name,age,gender):
data = "%s,gender%s,is%syears old,love db" % (name,gender,age)
print(data)
def bj(name,age,gender):
data = "%s,gender%s,is%syears old,love bj" % (name,gender,age)
print(data)
kc('bajie','20','man') #参数反复传递
db('bajie','20','man')
bj('bajie','20','man')
1.2.2.面向对象编程
class Bajie():
def __init__(self,name,age,gender): #类中的一种特殊方法, 当类名()加了个括号, 则该方法会被自动执行
self.name = name # __init__的作用: 把参数封装起来(叫做构造方法)
self.age = age
self.gender = gender
def kc(self):
data = "%s,gender%s,is%syears old,love kc" % (self.name, self.gender, self.age) #参数就是被封装到了self里面
print(data)
def db(self):
data = "%s,gender%s,is%syears old,love db" % (self.name, self.gender, self.age)
print(data)
def bj(self):
data = "%s,gender%s,is%syears old,love bj" % (self.name, self.gender, self.age)
print(data)
obj = Bajie('bajie','20','man') #self 就是obj, 执行完__init__后, 参数就被封装到了self里,就是封装到了obj里
print(obj.name) #参数就是被封装到了obj里面
print(obj.age)
print(obj.gender)
obj.kc()
obj.db()
obj.bj()
1.2.3.总结
1).构造方法
class Foo:
def __init__(self,name): #构造方法, 目的是进行数据初始化
self.name = name
self.age = 18
obj = Foo('bajie')
print(obj.age)
#通过构造方法, 可以将数据进行打包,以后使用时, 去其中获取即可
class Bar:
pass
obj = Bar()
2).构造方法的应用: 当多个方法有共同参数的时候可以用
class File_Handler:
def __init__(self, file_path):
self.file_path = file_path
self.f = open(file_path, 'rb') #文件句柄经常打开, 就可以先打开,然后放到构造方法中,以供在方法中调用
def read_first(self):
self.f.readline()
pass
def read_last(self):
self.f.readline()
pass
def read_second(self):
self.f.readline()
pass
obj = File_Handler(r'C:\Users\THINKPAD\PycharmProjects\s15\day02\while.py')
obj.read_first()
obj.read_last()
obj.read_second()
obj.f.close()
2).构造方法的应用: 对数据进行封装给其他函数使用时
#函数参数的封装*arg **kwargs
def func(*args):
args[2]
args[5]
def func(**kwargs):
kwargs['k1']
kwargs['k2']
#面向对象__init__()的封装
def func(obj):
print(obj.k1)
print(obj.k2)
print(obj.k6)
class Foo:
def __init__(self,k1,k2,k6):
self.k1 = k1
self.k2 = k2
self.k6 = k6
obj = Foo(111,222,666)
func(obj)
1.3.对比三: 信息管理系统
#1.用户登录
#2.显示当前用户信息
#3.查看当前用户所有的账单
#4.购买抱枕
class User_info:
def __init__(self):
self.name = None
def shopping(self):
print('%s buy a baozhen' % (self.name,))
def info(self):
print('current user is: %s' % (self.name,))
def account(self):
print('%s s account is ... ...' % (self.name,))
def login(self):
user = input('user: ')
password = input('password: ')
if password == 'bajie123':
self.name = user
print('successful')
prompt = '''
1.显示当前用户信息
2.查看当前用户所有的账单
3.购买抱枕
please enter your choice(1/2/3):
'''
while True:
choice = input(prompt)
if choice == '1':
self.info()
elif choice == '2':
self.account()
elif choice == '3':
self.shopping()
else:
print('choice is out of range, please choice again!')
else:
print('incorrect')
obj = User_info()
obj.login()
1.3.1.总结: 类中的方法可以被类的方法调用
class Foo:
def func2(self):
print('func2')
def func1(self):
self.func2()
print('func1')
obj = Foo()
obj.func1()
2.面向对象代码如何编写
2.1.规则
class Foo:
def __init__(self,name):
self.name = name
def detail(self,msg):
print(self.name, msg)
obj = Foo('bajie')
obj.detail('detail message')
2.2.什么时候写? 如何写?
方式一: 归类+提取公共值(反向推导)
class File:
def __init__(self, file_path):
self.file_path = file_path
def file_read(self):
pass
def file_update(self):
pass
def file_delete(self):
pass
def file_add(self):
pass
class Excel:
def __init__(self, file_path):
self.file_path = file_path
def excel_read(self):
pass
def excel_update(self):
pass
def excel_delete(self):
pass
def excel_add(self):
pass
方式二: 在指定类中编写和当前类相关的所有代码(正向编写)
class Message:
def email(self):
pass
class Person:
def __init__(self,name,age,gen,flg):
self.name = name
self.age = age
self.gen = gen
self.flg = flg
def dajia(self):
self.flg -= 10
def practice(self):
self.flg += 60
bajie = Person('bajie',22,'man',1000)
wukong = Person('wukong',66,'man',666)
bajie.dajia()
bajie.practice()
wukong.practice()
print(bajie.flg)
print(wukong.flg)
3.面向对象三大特性:封装/继承/多态
3.1.封装:体现了两点
1)将相关功能封装到一个类中
class Message:
def email(self):pass
def msg(self):pass
def wechart(self):pass
2)将数据封装到一个对象中
class Person:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
obj = Person('bajie',33,'man')
print(obj.name)
3.2.继承
3.2.1.基本使用: 为了复用
class Super_base:
def f3(self):
print('in f3')
class Base(Super_base): #父类,基类
def f2(self):
print('in f2')
class Foo(Base): #子类,派生类 #父类写到括号里
def f1(self):
print('in f1')
obj = Foo()
obj.f1() #先在自己类中找
obj.f2() #没有再去父类找
obj.f3()
3.2.2.为何要有继承: 为了复用, 提高代码的重用性
class Base:
def f1(self): #如果Foo和Bar都有f1的功能, 那么就可以写到父类里面, 子类可继承f1方法
pass
class Foo(Base):
def f2(self):
pass
class Bar(Base):
def f3(self):
pass
3.2.3.多继承
class Base1:
def show(self):
print('base1 show')
class Base2:
def show(self):
print('base2 show')
class Foo(Base1,Base2): #多个父层,逗号分隔
pass
obj = Foo()
obj.show() #当父层有相同方法的时候, 自己没有时, 先找左边的父层中的方法执行
3.2.4.继承练习1
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f2() #都可执行
obj.f1()
obj = Base()
obj.f1()
#obj.f2() #找不到f2, 子类会去父类找,但是父类不会去子类找
3.2.4.继承练习2
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f3(self):
print('foo.f3')
def f2(self):
print('foo.f2')
self.f3() #self 就是obj. obj是哪个类的对象,就从哪个类开始找
obj = Foo()
obj.f2()
3.2.4.继承练习3
class Base:
def f1(self):
print('base.f1')
def f3(self):
print('foo.f3')
class Foo(Base):
def f2(self):
print('foo.f2')
self.f3()
obj = Foo()
obj.f2()
3.2.4.继承练习4
class Base:
def f1(self):
print('base.f1')
def f3(self):
self.f1() #self 一直是obj, 不论在哪个类中
print('foo.f3')
class Foo(Base):
def f2(self):
print('foo.f2')
self.f3()
obj = Foo()
obj.f2()
3.2.4.继承练习5
class Base:
def f1(self):
print('base.f1')
def f3(self):
self.f1() #要先去Foo里面找, 因为self 是Foo类的对象
print('base.f3')
class Foo(Base):
def f1(self):
print('foo.f1')
def f2(self):
print('foo.f2')
self.f3()
obj = Foo()
obj.f2()
obj2 = Base()
obj2.f3()
3.2.4.总结:
self 是哪个类的对象, 那么他一直是哪个类的对象, 那么就从自己开始找,没有再去找父类
3.2.4.继承练习6
class Base1:
def f1(self):
print('base1 f1')
def f2(self):
print('base1 f2')
class Base2:
def f1(self):
print('base2 f1')
def f2(self):
print('base2 f2')
def f3(self):
print('base2 f3')
self.f1()
class Foo(Base1,Base2):
def f0(self):
print('foo f0')
self.f3()
obj = Foo()
obj.f0()
3.2.5.总结:
1).继承的编写
class Foo(父类):pass
2).支持多继承(先找左)(c3算法找顺序)
3).为什么要有多继承: 提高代码的重用性
4).练习部分: 找self到底是谁的对象, 就先从哪开始找
3.3.多态:
在python中不用多说, python原生就支持
多种状态(形态): args的多态性
鸭子模型, 只要可以嘎嘎叫就是鸭子
def func(arg):
arg.send() #从这还不知道arg是什么类型
arg[0] #只知道有arg有这个属性和方法: 他可以是列表也可以是元组和字符串,这个参数可以是多个类型, 只要他支持这些功能就足够了
func([1,2,3]) #这里的参数就是对象: 是列表的对象
func('bajieaishuishui') #这里的参数就是对象: 是字符串的对象
func((1,)) #这里的参数就是对象: 是元组的对象
class Foo1:
def f1(self):pass
class Foo2:
def f1(self):pass
class Foo3:
def f1(self):pass
def func(arg):
arg.f1()
obj = Foo1() #obj = Foo2() #obj = Foo3()
func(obj)
3.3.1.总结: 由于python原生就是支持多态, 所以没有特殊性; 但是在java里面: 他只能传一种形态, 这时候多态就变得有意义了