zoukankan      html  css  js  c++  java
  • 第十二章 面向对象

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

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

    举例:开发一个消息提醒的功能(邮件/短信/微信)
      函数:
    def email(em, text):
        """
        发送邮件
        :return:
        """
        print(em, text)
    def msg(tel, text):
        """
        发送短信
        :return:
        """
        print(tel, text)
    def wechat(num, text):
        """
        发送微信
        :return:
        """
        print(num, text)
    # 编写功能:向所有的联系方式发送天气
    if True:
        msg('188888888', '今天有小雨')
        email('hao123@163.com.com', '今天有小雨')
        wechat('xxxx', '今天有小雨')
    面向对象:
    class Message:
        def email(self, em, text):
            """
            发送邮件
            :return:
            """
            print(em,text)
        def msg(self, tel, text):
            """
            发送短信
            :return:
            """
            print(tel,text)
        def wechat(self, num, text):
            """
            发送微信
            :return:
            """
            print(num,text)
    # 编写功能:向所有的联系方式发送天气
    if True:
        obj = Message()
        obj.email('hao123@163.com', '今天有小雨')
        obj.msg('188888888', '今天有小雨')
        obj.wechat('xxxx', '今天有小雨')

    对比:

    函数:定义简单、调用简单
    面向对象:定义复杂、调用复杂 好处:归类,将某些类似的函数功能写在一起

    总结:

      1 函数式编程可能会比面向对象好
      2. Python中支持两种编程方式
      3. 面向对象方式格式:
    定义:
      class 类名: # 定义了一个类
         def 函数名(self): # 在类中编写一个“方法”
          pass
    调用:
      x1 = 类名() # 创建了一个对象(实例化一个对象)
      x1.函数名() # 通过对象调用其中一个方法
    构造方法:
      class Foo:
         def __init__(self, name): # 构造方法,目的进行数据初始化
          self.name = name
          self.age = 18
      obj = Foo("久末") # 给类名加括号,默认调用构造方法
    通过构造方法,可以将数据进行打包,以后使用时,去其中获取即可
    应用:
      1、将数据封装到对象中,以供自己在方法中使用
    class FileHandler:
        def __init__(self, file_path):
            self.file_path = file_path
            self.f = open(self.file_path, 'rb')
    
        def read_first(self):
            # self.f.read()
            # ...
            pass
    
        def read_last(self):
            # self.f.read()
            # ...
            pass
    
        def read_second(self):
            # self.f...
            # ...
            pass
        
    obj = FileHandler('C:/xx/xx.log')
    obj.read_first()
    obj.read_last()
    obj.read_second()
    obj.f.close()
      2、将数据封装到对象中,供其他函数调用
    class FileHandler:
        def __init__(self, file_path):
            self.file_path = file_path
            self.f = open(self.file_path, 'rb')
        def read_first(self):
            # self.f.read()
            # ...
            pass
        def read_last(self):
            # self.f.read()
            # ...
            pass
        def read_second(self):
            # self.f...
            # ...
            pass
    obj = FileHandler('C:/xx/xx.log')
    obj.read_first()
    obj.read_last()
    obj.read_second()
    obj.f.close()

    2. 面向对象如何编写:

    方式一:先归类,然后提取公共值
    方式二:先在指定类中编写和当前类相关的所有代码,再提取公共值
    三大特性:
    封装:
    将相关功能封装到一个类中
    将数据封装到一个对象中
    继承:
    继承是为了复用,提高代码得重用性
    先找子类(派生类),后找父类(基类)—— 子类和父类是相对存在的
    先从子类中找,没有就从父类找
     
    多继承(只存在python中的功能):左边更亲
    多态:
    多种形态或者多种状态
    鸭子模型:只要可以嘎嘎嘎叫的就是鸭子
    二、类成员
    注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份
    class Foo:
        # 方法
        def __init__(self, name):
            # 实例变量/字段
            self.name = name
        # 方法
        def func(self):
            pass
    # obj,Foo类的对象
    # obj,Foo类的实例
    obj = Foo('jiumo')

    1. 变量(字段):

    字段包括实例变量和静态变量,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
    由上图可是:
    • 静态变量在内存中只保存一份
    • 实例变量在每个对象中都要保存一份
    应用场景: 通过类创建对象时,如果每个对象都具有相同的变量,那么就使用静态变量
    # 类变量/实例变量
    class Foo:
        # 类变量/静态字段
        country = '中国'
        # 方法
        def __init__(self, name):
            # 实例变量/字段
            self.name = name
        def func(self):
            pass
    
    obj1 = Foo('jiumo')
    obj2 = Foo('王XX')
    obj1.country = '美国'
    print(obj1.country)
    print(obj2.country)
    
    obj1 = Foo('jiumo')
    obj2 = Foo('王XX')
    Foo.country = '美国'
    print(obj1.country)
    print(obj2.country)
    ==>美国
    中国
    美国
    美国
      实例变量(字段)
        - 公有实例变量(字段)
    # 公有实例变量(字段)
    class Foo:
        def __init__(self, name):
            self.name = name
            self.age = 123
         # 内部调用
        def func(self):
            print(self.name)
    obj = Foo("jiumo")
    # 外部调用
    print(obj.name) # jiumo
    print(obj.age)  # 123
    obj.func()  # jiumo
        - 私有实例变量(字段)
    # 私有实例变量(字段)
    class Foo:
        def __init__(self, name):
            # 定义为私有
            self.__name = name
            self.age = 123
         # 内部调用
        def func(self):
            print(self.__name)
    obj = Foo("jiumo")
    # 外部不可直接调用
    # print(obj.name)     # 报错AttributeError: 'Foo' object has no attribute 'name'
    print(obj.age)
    obj.func()  # 间接访问:让func帮助执行内部私有的__name  就相当在类的内部有认识的”关系” 间接的得到想要的内容
      类变量(静态字段)
        - 公有类变量(静态字段)
    # 默认公有类变量(字段)
    class Foo:
        country = "中国"
        def __init__(self):
            pass
        def func(self):
            # 内部调用
            print(self.country)
            print(Foo.country)  # 推荐
    # 外部调用
    print(Foo.country)    # 中国
        - 私有类变量(静态字段)
    # 私有
    class Foo:
        __country = "中国"
        def __init__(self):
            pass
        def func(self):
            # 内部调用
            print(self.__country)
            print(Foo.__country)  # 推荐
    # 外部无法直接调用
    # print(Foo.__country)
    obj = Foo()
    obj.func(
    准则:
    实例变量(字段)访问时,使用对象访问,即:obj1.name
    类变量(静态字段)访问时,使用类访问,即:Foo.country(实在不方便时才使用对象)
    易错点:
    obj1 = Foo('jiumo')
    obj2 = Foo('王XX')
    
    obj1.name = '老王'
    print(obj1.name)
    print(obj2.name)
    ==>老王
    王XX
    什么时候用类变量:
    当所有对象中有共同的字段,并且值永远同步,那么可以使用类变量
    父类中的私有字段子辈无法知道,但是可以通过调用父类得到
    # 子类也不能直接调用父类的私有字段
    class Bsae(object):
        __secret = "RMB"
    class Foo(Bsae):
        def func(self):
            # print(self.__secret)  # AttributeError: 'Foo' object has no attribute '_Foo__secret'
            print(Foo.__secret)     # AttributeError: type object 'Foo' has no attribute '_Foo__secret'
    obj = Foo()
    obj.func()
    # 同样可以利用间接调用的方法得到私有字段
    class Bsae(object):
        __secret = "RMB"
        def money(self):
            print(Bsae.__secret)
    class Foo(Bsae):
        def func(self):
            pass
    obj = Foo()
    obj.money()

    2. 方法

    实例方法
    静态方法
    1. 定义时:
    - 方法上方写 @staticmethod
    - 方法参数可有可无
    2. 调用时:
    - 类.方法名() # 推荐使用
    - 对象.方法名()
    3. 什么时候使用静态方法:
    - 无需调用对象中封装的值
    - 类方法
    1. 定义时:
    - 方法上方写:@classmethod
    - 方法的参数:至少有一个cls参数
    2. 执行时:
    - 类名.方法名 # 默认会将当前类传到参数中
    3. 什么时使用类方法:
    - 如果在方法中会使用到当前类,那么就可以使用类方法
    # 没必要写实例方法
    class Foo(object):
        def __init__(self, name):
            self.name = name
        def func(self):
            print('实例方法')   # 没有用到构建方法中的值
    obj = Foo('jiumo')
    obj.func()
    # 有意义的实例方法
    class Foo(object):
        def __init__(self, name):
            self.name = name
        # 实例方法,最少有一个参数
        def func(self):
            print(self.name)    # wb
        # 静态方法,可以没有参数.  如果方法中无需使用对象中封装的值,那么就可以使用静态方法
        # 可以通过类直接调用,不需要实例化类这部操作
        @staticmethod
        def display():
            print('静态方法')    # 静态方法
        # 类方法
        @classmethod
        def train(cls, name):
    print(cls)        # <class '__main__.Foo'>
            print(name)        # 类方法
    # 实例方法
    obj = Foo('wb')
    obj.func()
    # 静态方法的调用
    Foo.display()
    # 类方法的调用
    Foo.train('类方法')
    
    ==>实例方法
    wb
    静态方法
    <class '__main__.Foo'>
    类方法
      方法的成员修饰符:方法也有公有方法和私有方法之分 用法同变量的成员修饰符
    # 私有的实例方法
    class Foo(object):
        def __init__(self):
            pass
        def __display(self,arg):
            print('私有方法',arg)
        def func(self):
            self.__display(123)
    obj = Foo()
    # obj.__display(123) # 无法访问
    obj.func()
    # 私有的静态方法
    class Foo(object):
        def __init__(self):
            pass
        @staticmethod
        def __display(arg):
            print('私有静态 方法',arg)    # 私有静态 方法 123
        def func(self):
            Foo.__display(123)
        @staticmethod
        def get_display():
            Foo.__display(888)  #私有静态 方法 888
    # Foo.__display(123) 报错
    obj = Foo()
    obj.func()
    
    Foo.get_display()

    3. 属性

    class Foo(object):
        def __init__(self):
            pass
        @property
        def start(self):
            return 1
        @property
        def end(self):
            return 10
    obj = Foo()
    print(obj.start)
    print(obj.end)
    1 编写时:
    - 方法上方写@property
    - 方法参数:只有一个self参数
    2 调用时:
    - 无需加括号 对象.方法
    3 应运场景:
    - 对于简单的方法,当无需传参且有返回值时

    4. 特殊方法

    class Foo():
        # 1.
        def __init__(self,a1, a2):
            self.a1 = a1
            self.a2 = a2
        # 2.
        def __call__(self, *args, **kwargs):
            print('wb', args, kwargs)
            return 123
        # 3.
        def __getitem__(self, item):
            print(item)
            return 123
        # 4.
        def __setitem__(self, key, value):  # 无返回值
            print(key, value, 123)
        # 5.
        def __delitem__(self, key): # 无返回值
            print(key)
        # 6.
        def __add__(self, other):
            return self.a1 + other.a1
        # 7.
        def __enter__(self):
            print('开始代码')
            return 999
        # 8.
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("结束代码")
    
        1.类名() 自动执行 __init__
        obj = Foo(1, 2)
        2.对象() 自动执行 __call__
        ret = obj(2018, 9, time = 2)
        print(ret)
        3.对象[] 自动执行 __getitem__
        ret = obj['wang']
        print(ret)
        4.对象['xx'] = 11 自动执行 __setitem__
        obj['k1'] = 123
        5.del 对象['xx'] = 11 自动执行 __delitem__
        del obj['wang']
        6.对象+对象       自动执行 __add__
        9. with 对象    自动执行__enter__ 和 __exit__
        obj = Foo(1, 2)
        with obj as f:
            print(f)
            print('内部代码')
    
        10.真正的构造方法 __new__
        class Foo(object):
            def __init__(self,a1, a2):
                print(1)
                self.a1 = a1
                self.a2 = a2
            def __new__(cls, *args, **kwargs):
                print(2)    # 执行到此处中断了
        Foo(1, 2)
    三、反射
    python中的反射功能是由以下四个内置函数提供的:
      - getattr(): 根据字符串为参数(第二个参数),去对象(第一个参数)中去寻找与之同名的成员
      - hasattr():根据字符串的形式,去判断对象中是否有成员
      - setattr():根据字符串的形式,动态的设置一个成员(内存)
      - delattr():根据字符串的形式,动态的删除一个成员(内存)
    class Foo(object):
        def __init__(self):
            self.name = 'jiumo'
        def func(self):
            return 'func'
    obj = Foo()
    # 检查是否含成员变量
    print(hasattr(obj, 'name'))    # True
    print(hasattr(obj, 'func'))    # True
    # 获取成员
    print(getattr(obj, 'name')) # jiumo
    print(getattr(obj, 'func')) # <bound method Foo.func of <__main__.Foo object at 0x0000016810C9C908>>
    # 设置成员
    setattr(obj, 'age', 18)
    print(getattr(obj, 'age'))  # 18
    setattr(obj, 'show', lambda num: num + 1)
    # print(getattr(obj, 'show')) # <function <lambda> at 0x0000016811EA47B8>
    # 删除成员
    delattr(obj, 'name')
    print(hasattr(obj, 'name')) # Fals
    delattr(obj, 'show')
    print(hasattr(obj, 'show')) # False
    
    # 反射实例说明:
    class Foo(object):
        func_lst = ['f1', 'f2', 'f3']
        def f1(self):
            print('注册成功')
        def f2(self):
            print('登陆成功')
        def f3(self):
            print('注销成功')
    obj = Foo()
    while True:
        print("""
        选择需要的功能:
            1. 注册
            2. 登陆
            3. 注销
        """)
        val = int(input("请输入要选择的功能:"))
        try:
            func_name = obj.func_lst[val-1]
    
            if hasattr(obj, func_name):
                func = getattr(obj, func_name)
                func()
            break
        except Exception:
            print("请输入正确的序号!")
  • 相关阅读:
    git 常用命令
    centos 7 mini 安装
    python打印杨辉三角
    python 求100内的素数/质数
    字符串与bytes
    format
    Python字符串格式化
    数据结构
    ARM工作模式
    C语言实现字符串逆序输出
  • 原文地址:https://www.cnblogs.com/jiumo/p/9545056.html
Copyright © 2011-2022 走看看