• 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支持多继承,注意查找顺序

     

  • 相关阅读:
    使用cwRsync实现windows下文件定时同步【转】
    asp.net负载均衡方案[转]
    SQL Server复制入门(一)----复制简介【转】
    使用ServiceStackRedis链接Redis简介 [转]
    Sqlserver事务发布实现数据同步
    C#MongoDB 分页查询的方法及性能
    C#基础-Func,Action
    OpenERP 的XML-RPC的轻度体验+many2many,one2many,many2one创建方式
    使用xml-rpc调试openerp模块中的函数
    Odoo(OpenERP)开发实践:通过XML-RPC接口访问Odoo数据库
  • 原文地址:https://www.cnblogs.com/canaan233/p/13748717.html
Copyright © 2020-2023  润新知