• python学习之路-8 面向对象之进阶


    上篇内容回顾和补充

    • 面向对象三大特性
      • 封装

      • 继承

      • 多态

        • 在python中没有多态的概念
        • 变量的类型允许为多种数据类型称之为多态
        # c#/java中的多态
        # 伪代码
        def func(int arg):
        	print(arg)
        func(123)  # 这样调用是没问题的
        func("aa")  # 这样是会报错的,因为func接受的参数必须是int类型
        
        那么如果func函数中的arg参数需要接受多种类型的参数,就需要按照下面的代码来搞:
        class A:
        	pass
        
        class B(A):
        	pass
        
        class C(A):
        	pass
        
        调用的时候:
        # arg参数,必须是A类型或A的子类类型
        def func(A arg):
        	print(arg)
        
        # 下面这三种方式都可以赋值给func函数
        # obj = B()
        # obj = C()
        # obj = A()
        
        func(obj)
        
        

    面向对象中的成员

    字段

    • 静态字段(类变量,多个对象共用一个字段,主要用于对象的变量内容都一样的时候)
    • 普通字段(对象变量)
    • 注意:静态字段在代码加载时就被创建了,而普通字段在类被实例化的时候才会被创建
    class Foo:
    	CC = 123  # 这个被称为字段(静态字段,属于类)
    	
    	def __init(self):
    		self.name = "aaa"  #这个被称为字段(普通字段,属于对象)
    
    • 静态字段和普通字段的使用
    class Province:
    	def __init__(self, name):
    		self.name = name
    		self.country = "中国"
    	
    # 实例化类
    hn = Province("河南")
    hn = Province("河北")
    hn = Province("山东")
    # 比如我需要实例化1000个像上面的对象,
    每个对象中都会存在一个self.country="中国"的变量,
    这样就会造成内存的浪费,这个时候就需要用静态字段来搞,代码如下:
    
    class Province:
    	country = "中国"
    	def __init__(self, name):
    		self.name = name
    	
    # 实例化类
    hn = Province("河南")
    hn = Province("河北")
    hn = Province("山东")
    # 这样所有的对象就会共用一个类变量country
    	
    
    • 普通字段和静态字段的访问规则
      • 普通字段只能用对象访问
      • 静态字段用类访问(万不得已的时候可以使用对象访问)

    方法

    • 普通方法,至少一个self,由对象执行
    class Province:
    	country = "中国"
    	
    	def __init__(self, name):
    		self.name = name
    	
    	def show(self):	# 普通方法,由对象去调用执行(方法属于类)
    		print(self.name)
    	
    # 调用普通方法
    p = Province()  # 实例化成一个对象
    p.show()   # 调用对象的show方法
    
    • 静态方法,使用staticmethod装饰器将该方法变为静态方法,由类直接调用执行(也可以用对象执行,轻易不要用)
    class Province:
    	country = "中国"
    	
    	def __init__(self, name):
    		self.name = name
    	
    	@staticmethod
    	def show(arg1, arg2):	# 静态方法  == 函数,放在这个位置,表示这个静态方法是跟Province类有关的
    		print(arg1, arg2)
    	
    # 执行静态方法
    Province.show(111, 222)
    
    • 类方法,静态方法的特殊形式,使用classmethod装饰器将该方法变为类方法,由类直接调用执行(也可以用对象执行,轻易不要用)
    class Province:
    	country = "中国"
    	
    	def __init__(self, name):
    		self.name = name
    	
    	@classmethod
    	def show(cls):	# 类方法,由类调用,最少要有一个参数cls,调用的时候这个参数不用传值,自动将类名赋值给cls
    		print(cls)
    	
    # 调用方法
    Province.show()
    

    属性

    • 将类中的方法变为一个属性,该属性的调用方法和字段是一样的
    # 使用装饰器 property 将一个方法变为属性,在调用改属性的时候不需要加括号调用,代码如下:
    	
    class Pager:
        """
        计算分页的功能
        """
    	
        def __init__(self, all_count):
            self.all_count = all_count
    	
    	
        @property
        def all_pager(self):
            """
            计算需要分几页,比如以每页10条为例子
            :return:
            """
            a1, a2 = divmod(self.all_count, 10)
            if a2 == 0:
                return a1
            else:
                return a1 + 1
    	
    p = Pager(101)
    ret = p.all_pager
    print(ret)
    
    • 给属性添加赋值、删除功能(第一种方式)
    class Pager:
    """
    计算分页的功能
    """
    
    def __init__(self, all_count):
        self.all_count = all_count
    
    @property		# 将一个方法变为属性
    def all_pager(self):
        """
        计算需要分几页,比如以每页10条为例子
        :return:
        """
        a1, a2 = divmod(self.all_count, 10)
        if a2 == 0:
            return a1
        else:
            return a1 + 1
    
    @all_pager.setter    # 让all_pager属性具有赋值的方法,提供一个关联方式,具体的创建变量的代码还是需要自己去写的
    def all_pager(self, value):
        print(value)
        
    @all_pager.deleter   # 让all_pager属性具有删除的方法, 将del和这个方法进行关联,具体的删除方法还是需要自己去写的
    def all_pager(self):
        print(“del all_pager”)
    
    p = Pager(101)
    ret = p.all_pager
    print(ret)
    	
    p.all_pager = "100"	# 给属性设置参数,会调用被装饰器@all_pager.setter装饰的方法
    del p.all_pager	# 删除  会调用被装饰器all_pager.deleter 装饰的方法
    
    • 给属性添加赋值、删除功能(第二种方式)
    class Pager:
        def __init__(self, all_count):
            self.all_count = all_count
    
        def f1(self):
            return 123
    
        def f2(self, value):
            pass
    
        def f3(self):
            pass
    
        foo = property(fget=f1, fset=f2, fdel=f3)  # 将foo实例化成一个属性,对foo进行调用的时候执行方法f1,对foo方法进行赋值的时候执行方法f2,对foo进行删除的时候调用方法f3
    
    p = Pager(100)
    result = p.foo
    print(result)
    
    p.foo = "aaa"
    
    del p.foo
    
    

    成员修饰符

    • 私有,任何私有的东西都不能够在本类外部进行调用
      • 私有字段

        • 私有普通字段 只能够在本类中调用,被继承的都不能够被调用
        class Foo:
        	def __init__(self, name):
        		self.__name = name  # 定义一个私有的普通字段
        	
        	def f1(self):
        		print(self.__name)
        
        class Bar(Foo):
        	def f2(self):
        		print(self.__name)   # 调用不到私有普通字段
        obj = Foo("aaa")
        print(obj.__name)   # 报错,私有字段只能够在本类中的方法进行调用
        obj.f1()	# 这个就是正常的
        
        • 私有静态字段 # 需要将一个方法变成静态方法,在静态方法中调用静态字段,然后在类外面通过调用类的静态方法,就可以访问类中的静态字段了
        class Foo:
            __cc = "123"		# 定义一个私有的静态字段
        
            def __init__(self, name):
                self.__name = name  
        
            @staticmethod
            def f1():
                print(Foo.__cc)
        
        
        # print(Foo.__cc) # 这样调用会报错
        Foo.f1()  # 这样就可以了
        
        
      • 私有方法

        • 私有普通方法
        class Foo:
        
            def __init__(self, name):
                self.name = name  # 定义一个私有的普通字段
        
            def __print(self):
                print(self.name)
        
            def f1(self):
                self.__print()
        
        
        obj = Foo("aaa")
        obj.f1()  # 通过调用类中的公有方法来执行私有方法
        
        
        • 私有静态方法
        class Foo:
        	
        	def __init__(self, name):
        	    self.name = name  # 定义一个私有的普通字段
        	
        	@staticmethod
        	def __f2(num):
        	    print(num)
        	
        	@staticmethod
        	def f3(num):
        	    Foo.__f2(num)
        
        Foo.f3(10)
        
    • 私有属性
    • 使用对象访问私有的字段或方法可以通过obj._类名私有方法 调用类中私有的字段和方法
    class Foo:
    
        """
        这是一个测试类
        """
    
        def __init__(self, name):
            self.name = name
            self.__age = 10
    
        def __print(self):
            print(self.name)
    
    obj = Foo("xx")
    print(obj._Foo__age)
    obj._Foo__print()
    

    特殊成员

    • __init__ 构造方法,也叫作初始化方法
    • __del__ 析构函数 垃圾回收
    • __doc__ 注释 对类的一个说明文档
    class Foo:
    
        """
        这是一个测试类
        """
    
        def __init__(self, name):
            self.name = name
    
    obj = Foo("xx")
    print(obj.__doc__)
    
    # 输出
        这是一个测试类
    
    • __class__ 返回该对象属于哪个类 使用方法:对象.class
    class Foo:
    
        def __init__(self, name):
            self.name = name
    
    obj = Foo("xx")
    print(obj.__class__)
    
    # 输出
    <class '__main__.Foo'>  # 表示本模块中的Foo类
    
    • __call__ 执行对象() 会调用__call__方法
    class Foo:
    
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            print("__call__", self.name)
    
    obj = Foo("xx")
    obj()
    
    
    • __str__ 直接print对象的时候会调用__str__方法,并且会将__str__方法的返回值赋值给obj进行输出
    class Foo:
    
        """
        这是一个测试类
        """
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return self.name
    
    obj = Foo("xx")
    print(obj)
    
    # 输出
    xx
    
    • __add__

    • __dict__

    class Foo:
    
        """
        这是一个测试类
        """
    
        def __init__(self, name, age):
            self.name = name
            self.__age = age
    
    obj1 = Foo("aaa", 100)
    obj2 = Foo("bbb", 101)
    
    ret = obj1.__dict__
    print(ret)
    
    # 输出
    {'_Foo__age': 100, 'name': 'aaa'}
    
    • __getitem__ 对字典通过key取值和列表通过切片取值底层的实现

      • 字典通过key取值
      class Foo:
      
          def __init__(self, name, age):
              self.name = name
              self.__age = age
      
          def __getitem__(self, item):
              print(item)
      
      
      obj1 = Foo("aaa", 100)
      
      obj1["xxx"]   # 会调用对象obj1的__getitem__方法 中括号内的参数赋值给item
      obj1[1:2]
      
      # 输出
      xxx
      slice(1, 2, None)	# slice是一个类
      
      • 列表通过切片取值
      
      class Foo:
      
          def __init__(self, name, age):
              self.name = name
              self.__age = age
      
          def __getitem__(self, item):
              print(type(item))
              print(item)
              print(item.start)
              print(item.stop)
              print(item.step)
      
      obj1 = Foo("aaa", 100)
      obj1[1:20:2]
      	
      # 输出
      <class 'slice'>
      slice(1, 20, 2)
      1
      20
      2
      
    • __setitem__ 对字典通过key设置值和列表通过切片设置值底层的实现

      • 字典通过key设置值
      class Foo:
          def __init__(self, name, age):
              self.name = name
              self.__age = age
      
          def __getitem__(self, item):
              print(type(item))
              print(item)
              print(item.start)
              print(item.stop)
              print(item.step)
      
          def __setitem__(self, key, value):
              print(key, value)
      
          def __delitem__(self, key):
              print("del", key)
      
      obj1 = Foo("aaa", 100)
      obj1["key"] = "value"
      
      # 输出
      key value
      
      • 列表通过切片设置值
      class Foo:
      
          def __init__(self, name, age):
              self.name = name
              self.__age = age
      
          def __getitem__(self, item):
              print(type(item))
              print(item)
              print(item.start)
              print(item.stop)
              print(item.step)
      
          def __setitem__(self, key, value):
              print(key, value)
              print(key.start)
              print(key.stop)
              print(key.step)
      
          def __delitem__(self, key):
              print("del", key)
      
      obj1 = Foo("aaa", 100)
      obj1[1:20] = [1, 2, 3]
      
      # 输出
      slice(1, 20, None) [1, 2, 3]
      1
      20
      None
      
    • __delitem__ 删除字典指定的key和列表指定的切片范围底层的实现方法

      • 删除字典指定的key
      class Foo:
      
      def __init__(self, name, age):
          self.name = name
          self.__age = age
      
      def __getitem__(self, item):
          print(type(item))
          print(item)
          print(item.start)
          print(item.stop)
          print(item.step)
      
      def __setitem__(self, key, value):
          print(key, value)
          print(key.start)
          print(key.stop)
          print(key.step)
      
      def __delitem__(self, key):
          print("del", key)
      
      obj1 = Foo("aaa", 100)
      del obj1["aaa"]
      
      # 输出
      del aaa
      
      • 删除列表指定的切片范围
      class Foo:
      
      def __init__(self, name, age):
          self.name = name
          self.__age = age
      
      def __getitem__(self, item):
          print(type(item))
          print(item)
          print(item.start)
          print(item.stop)
          print(item.step)
      
      def __setitem__(self, key, value):
          print(key, value)
          print(key.start)
          print(key.stop)
          print(key.step)
      
      def __delitem__(self, key):
          print("del", key)
          print(key.start)
          print(key.stop)
          print(key.step)
      
      obj1 = Foo("aaa", 100)
      del obj1[1:20]
      
      # 输出
      del slice(1, 20, None)
      1
      20
      None
      
    • __iter__ 含有该方法,对象就可以被迭代了,默认不可迭代

    class Foo:
    
        def __iter__(self):
            yield 1
            yield 2
    
    obj = Foo()
    for item in obj:
        print(item)
    

    面向对象其他

    • isinstance 查看对象是否是类和该类父类的实例
    
    class Foo:
        pass
    
    obj = Foo()
    
    ret = isinstance(obj, Foo)
    print(ret)
    
    # 输出
    True
    
    • issubclass 查看前者是否是后者的子类
    class Foo:
        pass
    
    
    class Bar(Foo):
        pass
    
    
    ret = issubclass(Bar, Foo)
    print(ret)
    
    # 输出
    Trues
    
    • 执行父类的方法,在父类方法的基础之上再添加自己的内容
    class Foo:
    
        def f1(self):
            print("Foo.f1")
    
    
    class Bar(Foo):
    
        def f1(self):
            # 主动执行父类的f1方法
            super(Bar, self).f1()
            print("哈哈哈")
    
    obj = Bar()
    obj.f1()
    
    # 输出
    Foo.f1
    哈哈哈
    
    • 应用

      • 自定义类型,对字典进行补充 --> 有序字典
      class MyDict(dict):
      
      def __init__(self):
          self.li = []
          super(MyDict, self).__init__()   # 执行父类的__init__方法
      
      def __setitem__(self, key, value):
          self.li.append(key)
          super(MyDict, self).__setitem__(key, value) # 执行父类的__setitem__方法
      
      def __str__(self):
          temp_list = []
          for key in self.li:
              value = self.get(key)
              temp_list.append("'%s': %s" % (key, value,))
      
          temp_str = "{" + ",".join(temp_list) + "}"
          return temp_str
      
      obj = MyDict()
      obj["k1"] = 123    # 调用obj的__setitem__方法
      obj["k2"] = 456
      print(obj)  # 调用obj的__str__方法
      

    异常处理

    • try except
    • else 如果无异常,则执行
    • finally 不管是否有异常,都执行
    • raise 主动触发异常
    • assert 断言 条件成立不报错,反之报错

    设计模式之单例模式

    单例模式就是一个类只能创建一个实例化对象

    
    class Foo:
        instance = None
    
        def __init__(self, name):
            self.name = name
    
        @classmethod
        def get_instance(cls):
            if cls.instance:
                return cls.instance
            else:
                obj = cls("aaa")
                cls.instance = obj
                return obj
    
    obj1 = Foo.get_instance()
    print(obj1)
    
    obj2 = Foo.get_instance()
    print(obj2)
    
    # 输出
    <__main__.Foo object at 0x1007f9550>
    <__main__.Foo object at 0x1007f9550>
    
    
  • 相关阅读:
    尚硅谷《全套Java、Android、HTML5前端视频》
    OCM 学习练习题目
    本文转自 MyEclipse 2015反编译插件安装
    关闭VirtualBox虚拟机的时钟同步
    Oracle数据库的状态查询
    ORA-00845 MEMORY_TARGET not supported on this system 的解决
    Ehcache
    Oracle 列转行函数 Listagg()
    oracle数据库定时任务dbms_job的用法详解
    MySQL 处理海量数据时的一些优化查询速度方法
  • 原文地址:https://www.cnblogs.com/CongZhang/p/5617488.html
Copyright © 2020-2023  润新知