Python面向对象OOP

Python面向对象OOP

1、函数式编程和面向对象的对比

2、面向对象代码如何实现

3、面向对象三个特性:封装/继承/多态

 

(1) 面向过程

(2) 函数式编程 : 提高代码重用性

def func(arg):
    pass
​
func(1)
func(2)

(3) 为什么要将某些函数写在指定文件中

模块的划分,对函数进行归类

 

 

函数式编程和面向对象对比1(归类)

开发一个消息提醒的功能(邮件/短信/微信)

 

# 函数式编程
def email(em, text):
    """
    发送邮件
    """
    pass
​
​
def msg(tel, text):
    """
    发送短信
    """
    passdef wechat(num, text):
    """
    发送微信
    """
    pass# 编写一个功能,假设用户完成购买,发送短信,邮件,微信
if 1 == 1:
    msg('15851816236', "XXX完成购买")
    email('canaan@edu.com', "XXX完成购买")
    wechat('123456', "XXX完成购买")
 
# 面向对象编程
# 写一个类名,里面再写方法
class Message:
    
    def __init__(self):
        pass
    
    def email(self, em, text):
        pass
    
    def msg(self, tel, text):
        pass
    
    def wechat(self, num, text):
        pass# 调用
if 1 == 1:
    obj = Message()
    # obj会成为方法的第一个参数默认传入
    obj.msg('15851816236', "XXX完成购买")
    obj.email('canaan@edu.com', "XXX完成购买")
    obj.wechat('123456', "XXX完成购买")
 

函数的优点:定义简单,调用简单

面向对象:定义复杂,调用复杂;将某些类似的功能写在了一起(归类)

 

面向对象方式定义:

class 类名:  # 定义一个类
    
    def 函数名(self): # 在类中编写了一个方法
        pass
 

调用:

x1 = 类名()  # 创建了一个对象--实例化一个对象
x1.函数名()  # 通过对象,调用其中方法

 

示例:

def login():
    user = input("请输入用户名: ")
    pwd = input("请输入密码: ")
    if user == "Canaan" and pwd == "1234560":
        print("登录成功")
    else:
        print("登录失败")
login()

 

写一个面向对象版本的:

class Account:
    
    def login(self):
        user = input("请输入用户名: ")
        pwd = input("请输入密码: ")
        if user == "Canaan" and pwd == "1234560":
        print("登录成功")
    else:
        print("登录失败")
obj = Account()
obj.login()

 

函数式编程和面向对象对比2(数据封装)

 

需求:打印

canaan/233岁/女/喜欢打游戏

canaan/233岁/女/喜欢学习

 

函数式编程

"""
完成以下功能:
canaan/233岁/女/喜欢打游戏
canaan/233岁/女/喜欢学习
canaan/233岁/女/喜欢看电影
"""def games(name, age, gender):
    data = "%s, 今年%s岁, 性别%s,喜欢打游戏" %(name, age, gender)
    print(date)
​
def study(name, age, gender):
    data = "%s, 今年%s岁, 性别%s,喜欢学习" %(name, age, gender)
    print(date)
​
def move(name, age, gender):
    data = "%s, 今年%s岁, 性别%s,喜欢看电影" %(name, age, gender)
    print(date)
​
    
 
games('canaan', '233', '')
study('canaan', '233', '')
move('canaan', '233', '')
​
# 重复传参
# 如果可以把这些参数,放在指定的一堆,不再需要重复传递

 

面向对象编程

class Canaan:
    
    def __init__(self, name, age, gender):  # 实例化时,自动执行
        pass
    
    def games(self, name, age, gender):
        data = "%s, 今年%s岁, 性别%s,喜欢打游戏" %(name, age, gender)
        print(date)
​
    def study(self, name, age, gender):
        data = "%s, 今年%s岁, 性别%s,喜欢学习" %(name, age, gender)
        print(date)
​
    def move(self, name, age, gender):
        data = "%s, 今年%s岁, 性别%s,喜欢看电影" %(name, age, gender)
        print(date)
​
canaan = Canaan()

__init__方法什么时候被调用?

当实例化一个对象时,这个方法就会被自动执行

实例化:类名后面带一个括号,并赋值给一个对象名,就是一个实例化的过程

需要保证自动执行时,带着参数是正确的,也就是说,需要给这个对象实例化时,应该有的属性

obj = ClassName()

 

# 这里就不用加参数了,可以直接从对象容器(self)中取
def games(self, name, age, gender):
    pass
def games(self):
    data = "%s, 今年%s岁, 性别%s,喜欢打游戏" %(self.name, self.age, self.gender)
    print(data)
​
  
# 调用类的方法时,就不用传参了,三个参数都已经被打包放到了实例化的对象(在类中表现为self)中,类中的实例化方法,只要去self容器中取参数就可以了
canaan.games()
canaan.study()
canaan.move()

 

__init__方法的作用[构造方法]

把和实例化对象有关的值打包,初始化时就封装到了实例化对象(self)中,使用时用.获取即可

 

当方法被重复调用,需要多次重复传参

 

__init__方法中给一个默认值

class Foo:
    
    def __init__(self, name):
        self.name = name
        self.age = 18
 

obj = Foo("xxx")  # obj里面有两个值


class Bar:
    pass

obj = Bar()  # obj里面是空的

 

 

应用1:

如果许多方法,需要共同的参数时,可以改成面向对象的方式,把数据打包obj(self)中,其他的方法只要送self中进行获取

将数据封装到对象中,以便在方法中调用

class FileHandler:

    # 把一些共同的参数打包放到self里(实例化对象的属性里)
    def __init__(self, file_path):
        self.file_path = file_path
        self.f = open(self.file_path, 'rb')   # 把打开文件对象也封装在__init__()中,实例化方法进行调用就可以了

    # 这些方法又有共同的参数
    def read_first(self):
        # 如果这些方法,都需要打开文件这个操作
        # f = open(self.file_path, 'rb')
        self.f.read
        pass

    def read_last(self):
        # f = open(self.file_path, 'rb')
        self.f.read
        pass

    def read_second(self):
        # f = open(self.file_path, 'rb')
        self.f.read
        pass

obj = FileHandler('C:xxxx..')
obj.read_first()
obj.read_second()
obj.read_last()
obj.f.close()
 

应用2:

需要大量传参时

def func(a1, a2, a3, a4,...):
    pass


def func(*args):
    arg[1]  # 通过索引来获取传参
    arg[5]

def func(**kwargs):
    kwargs['a1']
    kwargs['a5']

   
func(a1='123', a2='456', a3='9')
# 这里就有一个打包的思想
 

如果使用面向对象

def new_func(arg):
    arg.k1
    arg.k2
    arg.k3

# 作用: 不会动态的传入,只会传入确定的
# 数据进行封装,给别人使用时
class Foo:
    
    def __init__(self, k1, k2, k3):
        self.k1 = k1
        self.k2 = k2
        self.k3 = k3
       
obj = Foo(111, 22, 3)
new_func(obj) # 参数打包到一个对象中
 

应用3:

需求:个人信息管理系统

1、用户登录

2、显示当前用户信息

3、查看当前用户所有的账单

4、购买一件商品

 

class UserInfo:
    def __init__(self):
        self.name = None  # 最开始无值,是空的
    
    def info(self):  # 现在实现方法就不用传参了,在类的内部可以进行封装
        print("当前用户为: %s" %(self.name, )) 

    def account(self):
        print("当前用户%s账单为xxx" %(self.name, ))

    def shopping(self):
        print("%s购买了一件商品" %(self.name, ))
    
    def login(self):
        user = input("请输入用户名:")
        pwd = input("请输入密码:")
        if pwd == "123456":
            self.name = user  # 不仅能从封装的self中获取值,还是可以继续在self里面封装
            while True:
                print("""
                    1、查看用户信息
                    2、查看用户账单
                    3、购买商品
                """)
                num = int(input("请输入选择"))
                if num == 1:
                    self.info()  # 内部调用当前类中的"实例化方法", 等价于obj.info(), obj传递到类中就是self
                elif num == 2:
                    self.account()
                elif num == 3:
                    self.shopping()
                else:
                    print("序号不存在,请重新输入")

        else:
            print("登录失败")


canaan = UserInfo()
canaan.login()

 

小结:

class Foo:
    def func2(self):
        print("func2")
     
    def func1(self):
        self.func2()
        print("func1")
   
obj = Foo()
obj.func1()

 

self永远指的是实例化对象

 

 

面向对象的代码应该如何编写

a、规则

class Foo:
    
    def __init__(self, name):
        self.name = name
        
    def detail(self, msg):
        print(selg.name, msg)
        
      
obj = Foo('xxx')
obj.detail('Hello')
 

b、如何写?

方式1:归类+提取公共值

方式2:正向编写,在指定类中编写和当前类相关的所有代码,提取公共值

# 和发消息有关的
class Message:
    def email(self):
        pass

# 和人有关的   
class Person:
    def run(self):
        pass
 

面向对象的三大特性:封装、继承和多态

封装:

  • 将相关功能(方法),封装到一个类中

  • 将数据(属性)封装到一个对象中

继承:

# ############ 继承的基本使用 ############
class SuperBase:
    
    def f3(self):
        print("f3")


class Base(SuperBase):   # 父类/基类

    def f2(self):
        print("f2")

# 继承
class Foo(Base):  # 子类/派生类

    def f1(self):
        print("f1")

obj = Foo()
obj.f1()
obj.f2()  # 子类(自己)没有,就去父类找
obj.f3()  # 父类还是没有,就去父类的父类找

# 查找原则: 子类没有,就去父类找

为什么要有继承关系:为了复用,提高代码的重用性

# ############ 继承是为了提高代码的重用性 ############
class Base:

    def f1(self):
        pass

class Foo(Base):

    # def f1(self):
    #     pass

    def f2(self):
        pass

class Bar(Base):

    # def f1(self):  # 如果这里的f1和Foo类中的f1一模一样,那么这段代码就是重复的,没必要写两遍
    #     pass

    def f2(self):
        pass
 

继承中的多继承

# ############ 多继承 ############
# python可以继承多个

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()
 

继承练习

############ 练习1 ############
class Base:

    def f1(self):
        print("f1")


class Foo(Base):
    
    def f2(self):
        print("f2")

# # 1
# obj = Foo()
# obj.f2()  # 从自己开始找
# obj.f1()  # 自己没有找父类的

# 2
obj = Base()
obj.f1()
obj.f2()  # 出错,子类可以调用父类的方法,父类不能使用子类的方法

 

############ 练习2 ############

class Base:

    def f1(self):
        print("Base.f1")

class Foo:

    def f3(self):
        print("Foo.f3")
    
    def f2(self):
        print("Foo.f2")
        self.f3  # obj是哪个类(Foo)的对象,那么执行方法时,就从该类开始找

obj = Foo()
obj.f2()  # obj是哪个类(Foo)的对象,那么执行方法时,就从该类开始找

 

############ 练习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()  # 一定要看self是谁的对象,和"自己"无关,self是谁的对象就从哪里开始找

obj = Foo()
obj.f2()
############ 练习4 ############

class Base:

    def f1(self):
        print("Base.f1")
    
    def f3(self):
        self.f1()  # 这里的self还是obj,调用self方法时,在python中传递的就是实例化对象,因此这里的self还是Foo的对象
        print("Foo.f3")

class Foo(Base):

    def f2(self):
        print("Foo.f2")
        self.f3()

obj = Foo()
obj.f2()
 
############ 练习5 ############

class Base:

    def f1(self):
        print("Base.f1")
    
    def f3(self):
        self.f1()  # self中传入的是obj,而obj一直都是Foo类的对象,所以这里调用的是子类的f1()方法
        print("Base.f3")

class Foo(Base):

    def f1(self):
        print("Foo.f1")
    
    def f2(self):
        print("Foo.f2")
        self.f3()  # 由于Foo类中不存在f3()方法,这里使用的是Base类的f3()方法

obj = Foo()
obj.f2() # 类中的self并不是在哪个类中,调用的是哪个类的方法,而是属于哪个类的对象,就去哪个类中找

obj2 = Base()  # 属于Base类中的对象
obj2.f3()
 

弄清楚,self到底是哪个类的中的对象,就从该类开始找,自己没有,找父类

 

############ 练习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()  # self还是Foo的对象obj,因此还是先回去Foo类中,没找到再去按多继承的顺序从左到右找


# 多继承时,先找左边的
# self是哪个类的对象,就从哪个类开始找
class Foo(Base1, Base2):

    def f0(self):
        print("Foo.f0")
        self.f3()

obj = Foo()
obj.f0()

 

小结:

  • 类的继承编写:

    class Foo(父类):
        pass
  • 支持多继承:

    查找顺序:永远先从实例化的类开始找,然后再依次从左往右一次查找父类中的方法

    class Foo(Base1, Base2...)
  • 为什么要有多继承?

    提高代码重用性

多态:

多种形态或多种状态——鸭子模型(只要可以"嘎嘎"叫,那就是鸭子)

def func(arg):  # python原生就支持多态
    arg.send()
    arg[0]

func([11, 33])
func((1, 2, 3))
func("abcd")

Python原生支持多态,所以没有特殊性,但是在Java或者别的语言中有限制

如果规定了类型,传参是可以是类对象,也可以是类的任何子类的对象

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)

 

1、面向对象编写

2、如果归类:类相关的功能(方法)+提供公共值(属性)

 

 

面向对象的成员和组合

1、面向对象解决什么问题:

  • 归类(一个类的方法封装一个类中方法)

  • 重复传参(封装到对象中,称为对象的属性)

  • 提高代码重用性(子类继承父类)

 

 

2、继承:当存在两个类或者多个类中,有一些共同的属性或者方法,为了避免代码重复编写,可以放到一个基类中

多态:本身Python原生支持多态,崇尚“鸭子模型”,体现到代码上,就是写一个函数,传参时无需指定类型,arg可以是多种类型,只要这个对象,带有自身的方法,就能进行调用

3、编写面向对象程序

归类+提供公共值

4、self指的到底是什么(一个实例的对象本身)

self在类外是一个对象,在类内也表现为一个实例对象本身,self是python帮助自动传递的,传递到类中,然后在类方法中进行传递,如果执行面向对象方法,必须由一个实例本身进行执行

xxx.func1()

5、python支持多继承,注意查找顺序

 

原文地址:https://www.cnblogs.com/canaan233/p/13748717.html