zoukankan      html  css  js  c++  java
  • 面向对象

    5.1 面向对象的基本知识

    5.1.1 基本概念

    1. 类:具有相同方法和属性的一类事物
    2. 对象(实例):一个拥有具体属性值和动作的具体个体
    3. 实例化:从一个类得到一个具体对象的过程

    5.1.2 基本格式

    # 定义类 
    class 类名:
        def 方法名(self,name):
            print(name)
            return 123
        def 方法名(self,name):
            print(name)
            return 123
        def 方法名(self,name):
            print(name)
            return 123
        
    # 调用类中的方法
    # 1.创建该类的对象
    obj = 类名()
    # 2.通过对象调用方法
    result = obj.方法名('alex')
    print(result)
    

    5.1.3 应用场景

    1. 应用场景:遇到很多函数,需要给函数进行归类和划分

    2. 补充:

      • 类和对象是什么关系?

        • 对象是类的一个实例
      • self是什么?

        • self就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数
      • 类内部代码会自上而下依次执行,类变量立即执行,方法需要调用内部代码才会执行

      • 类与类之间可以嵌套,执行遵循上条

      • 什么时候使用面向对象?

        • 函数(业务功能)比较多,可以使用面向对象来进行分类
        • 想要做数据封装(创建字典存储数据时,面向对象)
        • 游戏示例:创建一些角色并且根据角色需要再创建人物

    5.2面向对象的三大特性

    5.2.1 封装

    • 广义上的封装:类中的成员
    • 狭义上的封装:私有成员
    1. 对象的作用:存储一些值,方便以后自己使用

      class File(obje):
          def read(self):
              with open(self.xxxxx, mode='r', encoding='utf-8') as f:
                  data = f.read()
              return data
      
          def write(self, content):
              with open(self.xxxxx, mode='a', encoding='utf-8') as f:
                  f.write(content)
      
      # # 实例化了一个File类的对象
      obj1 = File()
      # # 在对象中写了一个xxxxx = 'test.log'
      obj1.xxxxx = "test.log"
      # # 通过对象调用类中的read方法,read方法中的self就是obj。
      # # obj1.read()
      obj1.write('alex')
      
      
      # 实例化了一个File类的对象
      obj2 = File()
      # 在对象中写了一个xxxxx = 'test.log'
      obj2.xxxxx = "info.txt"
      # 通过对象调用类中的read方法,read方法中的self就是obj。
      # obj2.read()
      obj2.write('alex')
      
    2. 封装的作用:将数据封装到对象,方便使用

      class Person:
          def __init__(self,n,a,g): # 初始化方法(构造方法),给对象的内部做初始化。
              self.name = n
              self.age = a
              self.gender = g
      
          def show(self):
              temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,)
              print(temp)
      
      # 类() 实例化对象,自动执行此类中的 __init__方法。
      p1 = Person('李兆琪',19,'男')
      p1.show()
      
      p2 = Person('利奇航',19,'男')
      p2.show()
      
    3. 总结

      • 如果写代码是,函数比较多比较乱

        • 可以将函数归类并放到ton规格类中
        • 函数如果有一个反复使用的公共值,则可以放到对象中
      • 面向过程编程

        # 示例:循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。
        # 以前的写法:
        USER_LIST = []
        while True:
            user = input('请输入用户名:')
            pwd = input('请输入密码:')
            email = input('请输入邮箱:')
            temp = {'username':user,'password':pwd,'email':email}
            USER_LIST.append(temp)
        for item in USER_LIST:
            temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],)
            print(temp)
        
      • 面向对象编程

        # 面向对象写法一:
        class Person:
            def __init__(self,user,pwd,email):
                self.username = user
                self.password = pwd
                self.email = email
        	
        USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
        while True:
            user = input('请输入用户名:')
            pwd = input('请输入密码:')
            email = input('请输入邮箱:')
            p = Person(user,pwd,email)
            USER_LIST.append(p)
        for item in USER_LIST:
            temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
            print(temp)
        
        
        
      • 面向对象写法二:

        class Person: def init(self,user,pwd,email): self.username = user self.password = pwd self.email = email
        def info(self): return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
        USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') p = Person(user,pwd,email) USER_LIST.append(p) for item in USER_LIST: msg = item.info() print(msg)

    5.2.2 继承

    • 所有的查找名字(调用方法和属性),都是先找自己,自己没有的找父类
    • 如果自己和父类都有,希望自己和父类都调用,就用super().指定类名字直接调用
    1. 基本内容

      # 父类(基类)
      class Base:
          def f1(self):
              pass
      # 子类(派生类)
      class Foo(Base):
          def f2(self):
              pass
      
      # 创建了一个子类的对象
      obj = Foo()
      # 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找
      obj.f2()
      obj.f1()
      
      # 创建了一个父类的对象
      obj = Base()
      obj.f1()
      
    2. 总结

      • 什么时候才能用到继承?

        • 多个类中如果有公共的方法,可以放到基类中避免重复编写
      • 继承关系中的查找方式的顺序时,注意事项

        • self到底是谁
        • self是哪个类创建的,就从此类开始找,自己没有就找父类
      • 多继承,如果一个派生类有多个基类,执行对象方法时,优先在在自己的类中找,如果没有就从左到右依次从基类中找

    3. 补充(python2与python3的区别十一):

      class Foo:
          pass
      class Foo(object):
          pass
      # 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。
      # 如果在python2中这样定义,则称其为:经典类
      class Foo:
          pass 
      # 如果在python2中这样定义,则称其为:新式类
      class Foo(object):
          pass
      # 新式类
          # 继承object
          # 支持super
          # 多继承 广度优先C3算法
          # mro方法
      # 经典类
          # py2中不继承object
          # 没有super语法
          # 多继承 深度优先
          # 没有mro方法
      
    4. 补充:

      • 新式类

        • 继承object

        • 支持super

        • 多继承 广度优先C3算法

        • mro方法

          class A:
              pass
          class B(A):
              pass
          class C(A):
              pass
          class D(B,C):
              pass
          d = D()
          print(d.mro())
          
      • 经典类

        • py2中不继承object
        • 没有super语法
        • 多继承 深度优先
        • 没有mro方法

    5.2.3 多态

    • 一个类表现出来的多种状态------->多个类表现出相似的状态
    1. 基本内容:多种形态 / 多种类型,python本身就是多态的

      def func(arg): # 多种类型,很多事物
          arg.send() # 必须具有send方法,呱呱叫
      
    2. 面试题:什么是鸭子模型?

      • 对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法),这就是鸭子模型。类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们想要的类型)

    5.3 成员

    5.3.1 类成员

    注意:在一般的类中,没有类名一律不能调用类中方法

    1. 类变量(静态字段)

      • 定义:写在类的下一级,和方法同一级

      • 访问

        • 类.类变量名()
        • 对象.类变量名()
        • 注意:如果对象中也有同名变量,则对象.类变量名()使用对象自己中的变量
      • 面试题

        # 面试题
        class Base:
            x = 1
            
        obj = Base()
        print(obj.x)    # 先去对象中找,没有再去类中找
        obj.y = 123     # 在对象中添加了一个y=123的变量
        obj.x = 123     # 在对象中添加了一个X=123的变量,无法修改类变量
        Base.x = 666    # 修改类变量,x = 666
        
      • 总结:

        • 找变量优先找自己的,自己没有再去父类或基类中找
        • 修改或赋值只能在自己内部设置
    2. 绑定方法(普通的方法)

      • 定义:至少有一个self对象
      • 执行:先实例化对象,对象.绑定方法()
      class Foo:
          def __init__(self):
              self.name = 123
      
          def func(self, a, b):
              print(self.name, a, b)
      
      obj = Foo()
      obj.func(1, 2)
      
    3. 静态方法

      • 定义

        • @staticmethod装饰器
        • 参数无限制(可以不传参数)
      • 执行:

        • 类.静态方法名()【推荐】
        • 对象.静态方法名()【不推荐,容易混淆】
      class Foo:
          def __init__(self):
              self.name = 123
      
          @staticmethod
          def f1():
              print(123)
      
      obj = Foo()
      Foo.f1()   # 推荐
      obj.f1()   # 不推荐
      
    4. 类方法

      • 定义:

        • @classmethod装饰器
        • 至少有cls参数(cls是当前类)
      • 执行:

        • 类.类方法名()【推荐】
        • 对象.类方法名()【不推荐,容易混淆】
      class Foo:
          def __init__(self):
              self.name = 123
             
          @classmethod
          def f2(cls,a,b):
              print('cls是当前类',cls)
              print(a,b)
      
      obj = Foo()
      Foo.f2(1,2)	   # 推荐
      obj.f2(1,2)    # 不推荐
      
      • 面试题(笔试)

        • 问:@classmethod和@staticmethod的区别?
        • 答:一个是类方法,一个是静态方法。定义: 类方法:用@classmethod做装饰器且至少有一个cls参数 静态方法:用@staticmethod做装饰器且参数无限制 调用: 类.方法直接调用,对象.方法也可以调用
    5. 属性

      • 定义:

        • @property
        • 只能有一个参数
      • 执行:

        • 对象.方法名
        • 后面不用加括号,只是减少点代码量
      class Foo:
          @property
          def func(self):
              print(123)
              return 666
      
      obj = Foo()
      result = obj.func
      print(result)
      
      • 应用:

        # 属性的应用
        class Page:
            def __init__(self, total_count, current_page, per_page_count=10):
                self.total_count = total_count
                self.per_page_count = per_page_count
                self.current_page = current_page
            @property
            def start_index(self):
                return (self.current_page - 1) * self.per_page_count
            @property
            def end_index(self):
                return self.current_page * self.per_page_count
        
        USER_LIST = []
        for i in range(321):
            USER_LIST.append('alex-%s' % (i,))
        
        # 请实现分页展示:
        current_page = int(input('请输入要查看的页码:'))
        p = Page(321, current_page)
        data_list = USER_LIST[p.start_index:p.end_index]
        for item in data_list:
            print(item)
        

    5.3.2 示例(对象)成员

    1. 实例成员:实例变量

    2. 实例(对象)之间的嵌套

      • 函数:参数可以任意值
      • 字典:对象和类都可以做字典的key和value
      • 一个类的对象作为另一个对象的是实例变量
      class School(object):
          def __init__(self,title,addr):
              self.title = title
              self.address = addr
              
      class ClassRoom(object):
          def __init__(self,name,school_object):
              self.name = name
              self.school = school_object
              
      s1 = School('北京','沙河')
      s2 = School('上海','浦东')
      s3 = School('深圳','南山')
      
      c1 = ClassRoom('全栈21期',s1)
      c1.name
      c1.school.title
      c1.school.address
      
      class StackConfig(object):
          list_display = '李邵奇'
          
          def changelist_view(self):
              print(self.list_display)
              
      class UserConfig(StackConfig):
          list_display = '利奇航'
      
      class AdminSite(object):
          def __init__(self):
              self._register = {}
      
          def registry(self,key,arg=StackConfig):
              self._register[key] = arg
      
          def run(self):
              for key,value in self._register.items():
                  obj = value()
                  obj.changelist_view()
      site = AdminSite()
      site.registry(1)
      site.registry(2,StackConfig)
      site.registry(3,UserConfig)
      site.run()
      

    5.3.3 特殊成员(就是为了能够快速实现某种功能而生的)

    1. __init__()

      • 初始化方法
      • 用途:用于给对象中赋值
      class Foo:
          def __init__(self,a1):
              self.a1 = a1
              
      obj = Foo('alex')
      
    2. __new__(),先于__init__执行

      • 构造方法
      • 用途:用于创建空对象
      class Foo(object):
          def __init__(self):
              self.x = 123
          def __new__(cls, *args, **kwargs):
              return object.__new__(cls)
      
      obj = Foo()     # 先执行__new__方法,再执行__init__方法
      
    3. __call__()

      • 对象后面加括号执行该方法
      class Foo(object):
          def __call__(self, *args, **kwargs):
              print('执行call方法')
      
      obj = Foo()
      obj()        # 对象后面加括号,执行__call__方法
      # 相当于Foo()()
      
      • 网站示例

        from wsgiref.simple_server import make_server
        
        def func(environ,start_response):
            start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
            return ['你好'.encode("utf-8")  ]
        
        class Foo(object):
            def __call__(self, environ,start_response):
                start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
                return ['你<h1 style="color:red;">不好</h1>'.encode("utf-8")]
        
        # 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
        server = make_server('127.0.0.1', 8000, Foo())
        server.serve_forever()
        
    4. __getitem__()、__setitem__()__delitem__

      class Foo(object):
          def __setitem__(self, key, value):
              pass
          def __getitem__(self, item):
              return 'uuu'
          def __delitem__(self, key):
              pass
      
      obj1 = Foo()
      obj1['k1'] = 123        # 内部会自动调用 __setitem__方法
      val = obj1['xxx']       # 内部会自动调用 __getitem__方法,用val接受返回值
      del obj1['ttt']         # 内部会自动调用 __delitem__ 方法
      
    5. __str__()

      • 只有在打印对象时,会自动调用此方法,并将其返回值在页面上显示出来
      class Foo(object):
          def __str__(self):
              return 'asdfasudfasdfsad'
      
      obj = Foo()
      print(obj)     # obj是一个对象,打印__str__方法的返回值
      
      class User(object):
          def __init__(self,name,email):
              self.name = name
              self.email = email
          def __str__(self):
              return "%s %s" %(self.name,self.email,)
          
      user_list = [User('二狗','2g@qq.com'),User('二蛋','2d@qq.com'),User('狗蛋','xx@qq.com')]
      for item in user_list:
          print(item)
      
    6. __repr__()

      • 如果有str和repr,打印对象 调用str方法,打印列表或其他对象容器,调用repr方法

      • 如果只有str,无论什么时候都是调用str,repr也是同理

      • 实际应用上,str面向对象,repr更多的是面向程序员

      • 打印使用str,调用使用repr

         class D(object):
             def __str__(self):
                 return "a __str__"
             def __repr__(self):
                return "a __repr__"
        
        >>> dr = D()
        >>> print dr
        a __str__
        >>> dr
        a __repr__
        
    7. __dict__()

      • 去对象中找到所有变量并将其转换为字典
      class Foo(object):
          def __init__(self,name,age,email):
              self.name = name
              self.age = age
      
      obj = Foo('alex',19)
      val = obj.__dict__     # 去对象中找到所有变量并将其转换为字典
      print(val)
      
    8. __enter__()__exit__()

      • 上下文管理
      # 面试题
      class Foo(object):
          def do_something(self):
              print('内部执行')      # 第三步
      
      class Context:
          def __enter__(self):
              print('进入')           # 第一步
              return Foo()
          def __exit__(self, exc_type, exc_val, exc_tb):
              print('推出')      # 第四步
      
      with Context() as ctx:
          print('内部执行')      # 第二步
          ctx.do_something()
      
    9. __add__

      • 两个对象相加是用到此方法
      class Foo(object):
          def __add__(self, other):    # self:obj1,other:obj2
              return 123      
          
      obj1 = Foo()
      obj2 = Foo()
      val  = obj1 + obj2    # 内部会自动调用 __add__方法,并用val接受返回值
      print(val)      # 123
      
    10. __iter__

    • 将一个对象变成可迭代对象时用到此方法
       class Foo:
           def __iter__(self):
               return iter([1,2,3,4])
       
       obj = Foo()
    

    5.3.4 成员修饰符

    1. 公有,所有的地方都能够访问到

    2. 私有,只有自己才可以访问到,修饰符:__

      # 示例一:
      class Foo:
          def __init__(self, name):
              self.__name = name
      
          def func(self):
              print(self.__name)
      
      obj = Foo('alex')
      # print(obj.__name),报错,无法访问
      obj.func()
      
      # 示例二:
      class Foo:
          __x = 1
          
          @staticmethod
          def func():
              print(Foo.__x)
      
      # print(Foo.__x),报错,无法访问
      Foo.func()
      
      # 示例三:
      class Foo:
      
          def __fun(self):
              print('msg')
      
          def show(self):
              self.__fun()
      
      obj = Foo()
      # obj.__fun(),报错,无法访问
      obj.show()
      
    3. 强制访问私有,中间街上 _类名

      class Foo:
          def __init__(self,name):
              self.__x = name
      
      obj = Foo('alex')
      print(obj._Foo__x)     # 强制访问私有实例变量
      

    5.4约束

    • 又名:Foo抽象类 / 接口类

    • 定义:就是给子类一个规范,让子类必须按照抽象类的规范来实现方法

    • 示例

      # 约束子类中必须写send方法,如果不写,则调用时候就报抛出 NotImplementedError 
      class BaseMessage(object):
          def send(self,a1):
              raise NotImplementedError('子类中必须有send方法')
              
      class Msg(BaseMessage):
          def send(self):
              pass
      
      class Email(BaseMessage):
          def send(self):
              pass
      
      class DingDing(BaseMessage):
          def send(self):
              print('钉钉')
          
      obj = Email()
      obj.send()
      

    5.5 反射

    • 根据字符串的总是去某个对象中操作其他成员

    • 方法:

      • 通过对象来获取实例变量、绑定方法

      • 通过类来获取模块的任意类变量、类方法、静态方法

      • 通过模块名来获取模块中的任意变量(普通方法、函数、类)

      • 通过本文件来获取本文件中的任意变量

        • getattr(sys.modules[__name__],’变量名‘)

    5.5.1 getattr(对象,字符串)

    • 根据字符串的形式去某个对象中获取该成员

      class Foo(object):
          def __init__(self,name):
              self.name = name
      obj = Foo('alex')
      
      # 获取变量
      v1 = getattr(obj,'name')
      # 获取方法
      method_name = getattr(obj,'login')
      method_name()
      
    • 补充:

      class Foo(object):
          def get(self):
              pass
      
      obj = Foo()
      # if hasattr(obj,'post'): 
      #     getattr(obj,'post')
      
      v1 = getattr(obj,'get',None) # 推荐
      print(v1)
      

    5.5.2 hasattr(对象,字符串)

    • 根据字符转的形式去某个是对象中判断是否有该成员

      from wsgiref.simple_server import make_server
      class View(object):
          def login(self):
              return '登陆'
          def logout(self):
              return '等处'
          def index(self):
              return '首页'
      
      def func(environ,start_response):
          start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
          obj = View()
          # 获取用户输入的URL
          method_name = environ.get('PATH_INFO').strip('/')
          if not hasattr(obj,method_name):
              return ["sdf".encode("utf-8"),]
          response = getattr(obj,method_name)()
          return [response.encode("utf-8")  ]
      
      # 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
      server = make_server('192.168.12.87', 8000, func)
      server.serve_forever()
      

    5.5.3 setattr(对象,字符串,值)

    • 根据字符串的形式去某个对象中设置 / 修改该成员

      class Foo:
          pass
      
      obj = Foo()
      obj.k1 = 999
      setattr(obj,'k1',123) # obj.k1 = 123
      print(obj.k1)
      

    5.5.4 delattr(对象,字符串)

    • 根据字符串的形式去某个对象中删除该成员

      class Foo:
          pass
      
      obj = Foo()
      obj.k1 = 999
      delattr(obj,'k1')
      print(obj.k1)
      

    5.5.5 python一切皆对象

    1. 对象的定义

      • 狭义:类实例化出来的就是对象

      • 广义:

        • 模块(py文件)及其内部成员
        • 包(文件夹)及其内部成员
        • 类及其内部成员
        • 狭义的对象
    2. python一切皆对象,所以以后象牙通过字符串的形式操作其内部成员都可以通过反射机制实现

    5.6 单例模式(设计模式)

    5.6.1 定义:无论实例化多少次,永远用的都是第一次实例化出的对象

    5.6.2 应用场景:数据库连接,数据库连接池

    5.6.3 单例模式标准

    class Singleton(object):
        instance = None
        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = object.__new__(cls)
            return cls.instance
    
    obj1 = Singleton()
    obj2 = Singleton()
    
    # 不是最终,加锁。
    
    • 文件连接池
    class FileHelper(object):
        instance = None
        def __init__(self, path):
            self.file_object = open(path,mode='r',encoding='utf-8')
    
        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = object.__new__(cls)
            return cls.instance
    
    obj1 = FileHelper('x')
    obj2 = FileHelper('x')
    

    5.6.4 通过模块导入的特性也可以实现单例模式:

    # jd.py
    class Foo(object):
        pass
    
    obj = Foo()
    
    
    # app.py
    import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj
    print(jd.obj)
    

    5.7 项目目录

    5.7.1 包及其内部文件示例

    1. 可执行文件:bin

      • 将所有的可执行文件放入其中
    2. 业务相关:src

      • 登录注册相关:account.py
      • 订单相关:order.py
      • 主程序:run.py
    3. 公共类库:lib

      • 分页功能
    4. 数据库:db

      • 用户资料:user.txt
    5. 配置:config

      • 设置:settings
    6. 日志存储:log

      • 所有的日志文件

    5.7.2 注意:每个可执行文件必须把项目目录加入sys.path中

    import os
    import sys
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    
  • 相关阅读:
    第四章 证券投资基金的监管
    第三章 证券投资基金类型
    第二章 证券投资基金概述
    第一章 金融、资产管理与投资基金
    第一章附录
    第1章 为什么研究货币、银行与金融市场
    最近值得珍惜的小事
    转_如何解决linux动态库版本控制
    爆裂鼓手
    修改jupyter notebook默认路径
  • 原文地址:https://www.cnblogs.com/borntodie/p/13560229.html
Copyright © 2011-2022 走看看