zoukankan      html  css  js  c++  java
  • 第042讲:魔法方法:算术运算1

    课题笔记:

    啥是工厂函数?

    len()是一个BIF,作用是返回参数的长度。type(len)的话返回

    如果说type(int)则他是返回一个class “type”。就如同

    C定义完了后就是一个类对象。所以所谓的“工厂函数”就是类对象。

    int(‘123’),在以前就是调用int函数,将参数转化为123这个整形。而现在不一样了,它是实例化int的这个对象,然后返回一个它示例后的对象。例如:

    >>> a = int('123')
    >>> b = int('456')
    >>> a +b
    579

    原来对象是可以进行计算的。

    Python的魔法方法还提供了让你自定义对象的数值处理,通过对我们这些魔法方法的一个重写,你可以自定义任何对象间的算术运算。

    例子:

    >>> class New_int(int):
        def __add__(self, other):
            return int.__sub__(self, other)
        def __sub__(self, other):
            return int.__add__(self, other)
    
        
    >>> a = New_int(3)
    >>> b = New_int(5)
    >>> a + b
    -2
    >>> a - b
    8

    我这边 可以不return  int的魔法方法吗?

    >>> class Try_int(int):
        def __add__(self, other):
            return self + other
        def __sub__(self, other):
            return self - other
    
        
    >>> a = Try_int(3)
    >>> b = Try_int(5)
    >>> a + b
    Traceback (most recent call last):
      File "<pyshell#34>", line 1, in <module>
        a + b
      File "<pyshell#31>", line 3, in __add__
        return self + other
      File "<pyshell#31>", line 3, in __add__
        return self + other
      File "<pyshell#31>", line 3, in __add__
        return self + other
      [Previous line repeated 1022 more times]
    RecursionError: maximum recursion depth exceeded
    >>> 

    结果出现了无限递归!去到了递归的最高层次就出来了,自动退出了。为什么会这样子呢?

    当a+b的时候出现加法,自动先调用前者a的一个add,先调用一个add 的一个魔法方法;那调用add 的话返回的是什么?返回的是self加上other,self是示例对象绑定的一个方式(绑定进来的方式),那么这个self就是绑定了这个a进来,other就是加法右边的数(也就是b);那return的又是a+b,这样就出现无限递归。

    后面会讲到关于属性的魔法方法,更要注意这些情况了。

    可以这样改:

    >>> class Try_int(int):
        def __add__(self, other):
            return int(self) + int(other) #也可以不用int这个other
        def __sub__(self, other):
            return int(self) - int(other)
    
        
    >>> a = Try_int(3)
    >>> b = Try_int(5)
    >>> a + b
    8
    >>> 

    测试题:

    0. 自 Python2.2 以后,对类和类型进行了统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数。请问所谓的工厂函数,其实是什么原理?

    工厂函数就是将参数实例化成对象,然后调用其中的魔法方法

    答:工厂函数,其实就是一个类对象。当你调用他们的时候,事实上就是创建一个相应的实例对象

    # a 和 b 是工厂函数(类对象) int 的实例对象
    >>> a = int('123')
    >>> b = int('345')
    >>> a + b
    468

    1. 当实例对象进行加法操作时,会自动调用什么魔法方法?

    自动调用__add__(self, other)

    答:对象 a 和 b 相加时(a + b),Python 会自动根据对象 a 的 __add__ 魔法方法进行加法操作。

    2. 下边代码有问题吗?(运行起来似乎没出错的说^_^)

    class Foo:
            def foo(self):
                    self.foo = "I love FishC.com!"
                    return self.foo
    
    >>> foo = Foo()
    >>> foo.foo()
    'I love FishC.com!'

    foo是Foo示例化的一个对象,foo.foo()就是调用Foo类里面的foo这个函数? self就是foo, self.foo就是对象foo的foo属性等于一串字符串,foo函数最后返回这个属性

    答:这绝对是一个温柔的陷阱,这种BUG比较难以排查,所以一定要注意:类的属性名方法名绝对不能相同!如果代码这么写,就会有一个难以排查的BUG出现了:

    class Foo:
            def __init__(self):
                    self.foo = "I love FishC.com!"
            def foo(self):
                    return self.foo
    
    >>> foo = Foo()
    >>> foo.foo()
    Traceback (most recent call last):
      File "<pyshell#21>", line 1, in <module>
        foo.foo()
    TypeError: 'str' object is not callable

    3. 写出下列算术运算符对应的魔法方法:

    运算符
    对应的魔法方法
    +
    __add__(self, other)
    -
    __sub__(self, other)
    *
    __mul__(self, other)
    /
    __truediv__(self, other)
    //
    __floordiv__(self, other)
    %
    __mod__(self, other)
    divmod(a, b)
    __divmod__(self, other)
    **
    __pow__(self, other[,modulo])
    <<
    __lshift__(self, other)
    >>
    __rshift__(self, other)
    &
    __and___(self, other)
    ^
    __xor___(self, other)
    |
     __or___(self, other)

    4. 以下代码说明 Python 支持什么风格?

    def calc(a, b, c):
            return (a + b) * c
    
    >>> a = calc(1, 2, 3)
    >>> b = calc([1, 2, 3], [4, 5, 6], 2)
    >>> c = calc('love', 'FishC', 3)
    >>> print(a)
    9
    >>> print(b)
    [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
    >>> print(c)
    loveFishCloveFishCloveFishC

    对象间可以进行相加

    答:说明 Python 支持鸭子类型(duck typing)风格。详见:【扩展阅读】鸭子类型(duck typing)

    动动手:

    0. 我们都知道在 Python 中,两个字符串相加会自动拼接字符串,但遗憾的是两个字符串相减却抛出异常。因此,现在我们要求定义一个 Nstr 类,支持字符串的相减操作:A – B,从 A 中去除所有 B 的子字符串。

    示例:

    >>> a = Nstr('I love FishC.com!iiiiiiii')
    >>> b = Nstr('i')
    >>> a - b
    'I love FshC.com!'

    自己写的:

    class Nstr(str):
        def __sub__(self, other):
            return str.split(self,other)

    答案:

    class Nstr(str):
        def __sub__(self, other):
            return self.replace(other, '')

    1. 移位操作符是应用于二进制操作数的,现在需要你定义一个新的类 Nstr,也支持移位操作符的运算:

    >>> a = Nstr('I love FishC.com!')
    >>> a << 3
    'ove FishC.com!I l'
    >>> a >> 3
    'om!I love FishC.c'

    答:只需要重载 __lshift__ 和 __rshift__ 魔法方法即可。

    class Nstr(str):
        def __lshift__(self, other):
            return self[other:] + self[:other]
    
        def __rshift__(self, other):
            return self[-other:] + self[:-other]

    2. 定义一个类 Nstr,当该类的实例对象间发生的加、减、乘、除运算时,将该对象的所有字符串的 ASCII 码之和进行计算:

    >>> a = Nstr('FishC')
    >>> b = Nstr('love')
    >>> a + b
    899
    >>> a - b
    23
    >>> a * b
    201918
    >>> a / b
    1.052511415525114
    >>> a // b
    1

    代码清单:

    class Nstr:
        def __init__(self, arg=''):
            if isinstance(arg, str):
                self.total = 0
                for each in arg:
                    self.total += ord(each)
            else:
                print("参数错误!")
    
        def __add__(self, other):
            return self.total + other.total
    
        def __sub__(self, other):
            return self.total - other.total
    
        def __mul__(self, other):
            return self.total * other.total
    
        def __truediv__(self, other):
            return self.total / other.total
    
        def __floordiv__(self, other):
            return self.total // other.total

    也可以这样写:

    class Nstr(int):
        def __new__(cls, arg=0):
            if isinstance(arg, str):
                total = 0
                for each in arg:
                    total += ord(each)
                arg = total
            return int.__new__(cls, arg)

    第二种方法是用了继承了int 的属性,利用new在之前就把字符串先转成了ASCII码,然后用int的属性,int类型是有加减乘除这些的。

    作者:Agiroy_70

    本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。

    博主的文章主要是记录一些学习笔记、作业等。文章来源也已表明,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。

    博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!

  • 相关阅读:
    linux运维、架构之路-Kubernetes离线、二进制部署集群
    linux运维、架构之路-Kubernetes集群部署
    创建SpringMVC项目过程
    Spring AOP使用方式
    Java动态代理
    Java工厂模式解耦 —— 理解Spring IOC
    Neural Turing Machine
    小米路由器mini刷锐捷
    目前深度学习开源数据集整理
    Spring编译后没有xml配置文件解决方法
  • 原文地址:https://www.cnblogs.com/hale547/p/13380591.html
Copyright © 2011-2022 走看看