zoukankan      html  css  js  c++  java
  • 第二章:Python高级编程-魔法函数

    笔记

    2.1 什么是魔法函数(网络用语)

    • 以双下划线开始,双下滑线结尾。魔法函数是为了增强一个类的特性。
    • 魔法函数可以随意定义某个类的特性,这些方法在进行特定的操作时会自动被调用。

    2.1.1 需求:封装一个员工列表,并遍历查看

    (1)不使用魔法函数方法

    #!usr/bin/env python
    #-*- coding:utf-8 _*-
    # __author__:lianhaifeng
    # __time__:2020/5/10 18:20
    class Company(object):
        def __init__(self, employee_list):
            self.employee = employee_list
    
    company = Company(["tom", "bob", "jane"])
    employee = company.employee
    for em in employee:
        print(em)
    

    (2)使用__getitem__(self, item)魔法函数

    #!usr/bin/env python
    #-*- coding:utf-8 _*-
    # __author__:lianhaifeng
    # __time__:2020/5/10 18:20
    class Company(object):
        def __init__(self, employee_list):
            self.employee = employee_list
    
        def __getitem__(self, item):
            return self.employee[item]
    
    company = Company(["tom", "bob", "jane"])
    for em in company:
        print(em)
            
    """
    在解释器执行到for语句时,解释器首先寻找对象的迭代器。
    虽然company对象没有迭代器,
    但是解释器会尝试去寻找__getitem__()这一魔法函数,
    有了这个魔法函数的对象就是一个可迭代的类型,即便没有迭代器,
    解释器会调用该魔法函数,直到其抛出异常结束。
    若注释__getitem__代码片段,则会抛出不可迭代异常。
    """
    

    注意:在案例中,魔法函数既不是属于<class 'Company'>,也不是从<class 'object'>基继承过来。是一个独立的存在,往类里放入魔法函数之后,会增强类的一些类型。魔法函数不需要我们显示调用。Python会识别对象或自定义类的魔法函数,并隐式调用。

    2.2 Python的数据模型以及数据模型对Python的影响

    • 实际上魔法函数是网络上通常的叫法,其实魔法函数只不过是Python数据类型的一个概念而已。

      """
      当实现了__getitem__(self, item)魔法函数,就可以使用for循环去遍历。魔法函数实际上会影响python语法的,或可以理解为Python语法实际上会识别一个对象或者说自定义类里的魔法函数。
      """
      #-*- coding:utf-8 _*-
      # __author__:lianhaifeng
      # __time__:2020/5/10 18:20
      # 使用__getitem__(self, item)魔法函数
      class Company(object):
          def __init__(self, employee_list):
              self.employee = employee_list
      
          def __getitem__(self, item):
              return self.employee[item]
      
      company = Company(["tom", "bob", "jane"])  # __getitem__(self, item) 实际上也是序列类型
      company1 = company[:2]     
      print(company1)
      
      """
      ['tom', 'bob']
      
      """
      
    • 如果不实现__getitem__(self, item)就会报错

      #!usr/bin/env python
      #-*- coding:utf-8 _*-
      # __author__:lianhaifeng
      # __time__:2020/5/10 18:20
      class Company(object):
          def __init__(self, employee_list):
              self.employee = employee_list
      
          # def __getitem__(self, item):
          #     return self.employee[item]
      
      company = Company(["tom", "bob", "jane"])
      company1 = company[:2]
      print(company1)
      
      """
      Traceback (most recent call last):
        File "E:/projects/vue-django/myproject/sample/chapter02/company03.py", line 14, in <module>
          company1 = company[:2]
      TypeError: 'Company' object is not subscriptable
      
      """
      
      #!usr/bin/env python
      #-*- coding:utf-8 _*-
      # __author__:lianhaifeng
      # __time__:2020/5/10 18:20
      class Company(object):
          def __init__(self, employee_list):
              self.employee = employee_list
      
          # def __getitem__(self, item):
          #     return self.employee[item]
      
      company = Company(["tom", "bob", "jane"])
      print(len(company))  # 没有定义__len__(self)或__getitem__(self, item)魔法函数时,这个语句会报错
      
      """
      Traceback (most recent call last):
        File "E:/projects/vue-django/myproject/sample/chapter02/company03.py", line 14, in <module>
          print(len(company))
      TypeError: object of type 'Company' has no len()
      """
      
    • 两种方式实现对象可len()
      (1)getitem(self, item) + 切片 实现
      (2)len(self, item) 实现
      在调用内置函数len()时,解释器首先会调用魔法函数__len__(self),若没有,则退一步,去不断调用__getitem__(self, item)直到抛出异常,len()函数返回执行次数。

      #!usr/bin/env python
      #-*- coding:utf-8 _*-
      # __author__:lianhaifeng
      # __time__:2020/5/10 18:20
      # 使用__getitem__(self, item)魔法函数 + 切片
      class Company(object):
          def __init__(self, employee_list):
              self.employee = employee_list
      
          def __getitem__(self, item):
              return self.employee[item]
      
      company = Company(["tom", "bob", "jane"])
      company1 =company[:]
      print(len(company1))
      
      """
      3
      """
      
      #!usr/bin/env python
      #-*- coding:utf-8 _*-
      # __author__:lianhaifeng
      # __time__:2020/5/10 18:20
      # 使用__len__(self)魔法函数
      class Company(object):
          def __init__(self, employee_list):
              self.employee = employee_list
      
          def __len__(self):
              return len(self.employee)
      
      company = Company(["tom", "bob", "jane"])
      print(len(company))
      
      """
      3
      """ 
      

    魔法函数会影响Python语法和其内置函数本身的。

    2.3 魔法函数一览

    2.3.1 非数学运算

    • 字符串表示 魔法函数提供了两个来应对开发模式的不同
      (1)repr 用于命令行模式,作用:输入对象名即可调用repr方法
        # jupyter或ipython 命令行终端运行
        class Company(object):
            def __init__(self, employee_list):
                self.employee = employee_list
        
            def __repr__(self):
                return ','.join(self.employee)
        
        company = Company(['tom', 'bob', 'jane'])
        company
        
        """
        tom,bob,jane
        """
      
      (2)__str__用于脚本,作用:print(对象名)即可调用str方法
        #!usr/bin/env python
        #-*- coding:utf-8 _*-
        # __author__:lianhaifeng
        # __time__:2020/5/10 18:20
        class Company(object):
            def __init__(self, employee_list):
                self.employee = employee_list
        
            def __str__(self):
                return ','.join(self.employee)
        
        company = Company(['tom', 'bob', 'jane'])
        print(company)  
        
        """
        tom,bob,jane
        """
      
      """
      魔法函数只要定义了,就不需要开发者调用,Python解释器自己知道什么时候调用它。
      """
      
      """
      集合、序列相关
      	__len__
      	__getitem__
      	__setitem__
      	__delitem__
      	__contains__
          
          
      迭代相关
      	__iter__
      	__next__
          
          
      可调用
      	__call__
          
          
      with上下文管理器
      	__enter__
      	__exit__
          
          
      数值转换
      	__abs__
      	__bool__
      	__int__
      	__float__
      	__hash__
      	__index__
          
          
      元类相关
      	__new__
      	__init__
          
          
      属性相关
          __getattr__
          __setattr__
          __getattribute__
          __setattribute__
          __dir__
          
          
      属性描述符
          __get__
          __set__
          __delete__
          
          
      协程
          __await__
          __aiter__
          __anext__
          __aenter__
          __aexit   
      """
      

    2.3.2 数学运算

    """
    数学运算在一般开发使用不多,在数据处理是用的比较多,这里简单举几个例子。
    """
    
    # ============== __abs__ Demo start ============
    class Nums(object):
        def __init__(self, num):
            self.num = num
            
        def __abs__(self):
            return abs(self.num)
        
        
    num = Nums(-1)
    print(abs(num))  # 结果:1
    # ============== __abs__ Demo end ============
    
    
    # ============== __add__ Demo start ============
    class MyVector(object):
        def __init__(self, x, y):
            self.x = x
            self.y = y
            
        def __add__(self, other_instance):
            re_vector = MyVector(self.x+other_instance.x, self.y+other_instance.y)
            return re_vector
        
        def __str__(self):
            return "x:{x}, y:{y}".format(x=self.x, y=self.y)
        
        
    first_vec = MyVector(1, 2)
    second_vec = MyVector(2, 3)
    print(first_vec+second_vec)  # 结果:x:3,y:5
    # ============== __add__ Demo end ============
    
    
    
    一元运算符
        __neg__    -
        __pos__    +
        __abs__   |x|
        
        
    二元运算符
        __lt__    <
        __le__    <=
        __eq__    ==
        __ne__    != 
        __gt__    > 
        __ge__    >=
        
        
    算术运算符
        __add__         +
        __sub__         -
        __mul__         * 
        __truediv__     /
        __floordiv__    // 
        __mod__         % 
        __divmod__      divmod() 
        __pow__         ** 或 pow()
        __round__       round()
    
    
    反向算术运算符
        __radd__ 
        __rsub__ 
        __rmul__ 
        __rtruediv__ 
        __rfloordiv__ 
        __rmod__ 
        __rdivmod__ 
        __rpow__
    
    
    增量赋值算术运算符
        __iadd__ 
        __isub__ 
        __imul__ 
        __itruediv__ 
        __ifloordiv__ 
        __imod__ 
        __ipow__
    
    
    位运算符
        __invert__    ~ 
        __lshift__    << 
        __rshift__    >> 
        __and__       & 
        __or__        | 
        __xor__       ^
    
    
    反向位运算符
        __rlshift__ 
        __rrshift__ 
        __rand__ 
        __rxor__ 
        __ror__
        
        
    增量赋值位运算符
        __ilshift__ 
        __irshift__ 
        __iand__ 
        __ixor__ 
        __ior__    
    

    2.4 len函数的特殊性

    len函数不仅仅调用__len__方法这么简单,len函数对于set dict list等Python原生数据结构做了内部的优化,其性能是非常高的。应为原生数据结构中,会有一个专门的字段来储存数据长度,那么len函数会直接去读取这个字段,而不会去遍历它。

  • 相关阅读:
    向强大的SVG迈进
    手把手教你写个小程序定时器管理库
    蒲公英 · JELLY技术周刊 Vol.11 Lighthouse 测试报告生成
    ES6语法——let和const
    北京天地益星面经
    JS的数据类型你真的懂了吗
    北京MedPeer凉经
    flex布局语法+实例
    面试官问:你有多少种方式实现三栏布局?
    CSS粘性定位
  • 原文地址:https://www.cnblogs.com/lianhaifeng/p/12866435.html
Copyright © 2011-2022 走看看