• 第42~43讲:课后作业


    第42讲:

    测试题部分:

    0. 自 Python2.2 以后,对类和类型进行了统一,做法就是将 int()、float()、str()、list()、tuple() 这些 BIF 转换为工厂函数。请问所谓的工厂函数,其实是什么原理?
    答:工厂函数,其实就是一个类对象。当你调用他们的时候,事实上就是创建一个相应的实例对象。

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

    1. 当实例对象进行加法操作时,会自动调用什么魔法方法?
    答:对象 a 和 b 相加时(a + b),Python 会自动根据对象 a 的 __add__ 魔法方法进行加法操作。

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

    1 class Foo:
    2         def foo(self):
    3                 self.foo = "I love FishC.com!"
    4                 return self.foo
    5 >>> foo = Foo()
    6 >>> foo.foo()
    7 'I love FishC.com!'

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

     1 class Foo:
     2         def __init__(self):
     3                 self.foo = "I love FishC.com!"
     4         def foo(self):
     5                 return self.foo
     6 >>> foo = Foo()
     7 >>> foo.foo()
     8 Traceback (most recent call last):
     9   File "<pyshell#21>", line 1, in <module>
    10     foo.foo()
    11 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__(a, b)
    **
    __pow__(self, other[, modulo])
    <<
    __lshift__(self, other)
    >>
    __rshift__(self, other)
    &
    __and__(self, other)
    ^
    __xor__(self, other)
    |
    __or__(self, other)


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

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

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

    动动手部分:

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

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

    答:只需要重载 __sub__ 魔法方法即可。

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

    replace方法的功能是字符串替换,这里把字母‘i’全部替换成空字符串了

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

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

    答:只需要重载 __lshift__ 和 __rshift__ 魔法方法即可。U;<Lfr^#

    1 class Nstr(str):
    2     def __lshift__(self, other):
    3         return self[other:] + self[:other]
    4     def __rshift__(self, other):
    5         return self[-other:] + self[:-other]

    通过字符串切片和字符串连接符‘+’完成了移位操作。

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

     1 >>> a = Nstr('FishC')
     2 >>> b = Nstr('love')
     3 >>> a + b
     4 899
     5 >>> a - b
     6 23
     7 >>> a * b
     8 201918
     9 >>> a / b
    10 1.052511415525114
    11 >>> a // b
    12 1

    代码清单:u$TOVh?Z

     1 class Nstr(str):
     2     def __init__(self, arg=''):
     3         if isinstance(arg, str):
     4             self.total = 0
     5             for each in arg:
     6                 self.total += ord(each)
     7         else:
     8             print("参数错误!")
     9     def __add__(self, other):
    10         return self.total + other.total
    11     def __sub__(self, other):
    12         return self.total - other.total
    13     def __mul__(self, other):
    14         return self.total * other.total
    15     def __truediv__(self, other):
    16         return self.total / other.total
    17     def __floordiv__(self, other):
    18         return self.total // other.total

    当然,你还可以这样做::

    1 class Nstr(int):
    2     def __new__(cls, arg=0):
    3         if isinstance(arg, str):
    4             total = 0
    5             for each in arg:
    6                 total += ord(each)
    7             arg = total
    8         return int.__new__(cls, arg)

    第43讲

    测试题部分:

    0. 对象相加(a + b),如果 a 对象有 __add__ 方法,请问 b 对象的 __radd__ 会被调用吗?
    答:不会!
    实验如下:DH)eE0=

     1 >>> class Nint(int):
     2         def __radd__(self, other):
     3                 print("__radd__ 被调用了!")
     4                 return int.__add__(self, other)
     5 >>> a = Nint(5)
     6 >>> b = Nint(3)
     7 >>> a + b
     8 8
     9 >>> 1 + b
    10 __radd__ 被调用了!
    11 4


    1. Python 什么时候会调用到反运算的魔法方法?
    答:例如 a + b,如果 a 对象的 __add__ 方法没有实现或者不支持相应的操作,那么 Python 就会自动调用 b 的 __radd__ 方法。

    2. 请问如何在继承的类中调用基类的方法?
    答:使用 super() 这个 BIF 函数。

    1 class Derived(Base):
    2     def meth (self):
    3         super(Derived, self).meth()

    3. 如果我要继承的基类是动态的(有时候是 A,有时候是 B),我应该如何部署我的代码,以便基类可以随意改变。
    答:你可以先为基类定义一个别名,在类定义的时候,使用别名代替你要继承的基类。如此,当你想要改变基类的时候,只需要修改给别名赋值的那个语句即可。顺便说一下,当你的资源是视情况而定的时候,这个小技巧很管用。
    举个例子:

    1 BaseAlias = BaseClass  # 为基类取别名
    2 class Derived(BaseAlias):
    3     def meth(self):
    4         BaseAlias.meth(self)  # 通过别名访问基类
    5         ...

    4. 尝试自己举一个例子说明如何使用类的静态属性。(一定要自己先动手再看答案哦^_^)
    答:类的静态属性很简单,在类中直接定义的变量(没有 self.)就是静态属性。引用类的静态属性使用”类名.属性名”的形式。
    类的静态属性应用(计算该类被实例化的次数):;

    1 class C:
    2     count = 0  # 静态属性
    3     def __init__(self):
    4         C.count = C.count + 1  # 类名.属性名的形式引用
    5     def getCount(self):
    6         return C.count

    5. 尝试自己举例说明如何使用类的静态方法,并指出使用类的静态方法有何有点和需要注意的地方?(一定要自己先动手再看答案哦^_^)
    答:静态方法是类的特殊方法,静态方法只需要在普通方法的前边加上 @staticmethod 修饰符即可。

    1 class C:
    2         @staticmethod  # 该修饰符表示 static() 是静态方法
    3         def static(arg1, arg2, arg3):
    4                 print(arg1, arg2, arg3, arg1 + arg2 + arg3)
    5         def nostatic(self):
    6                 print("I'm the f**king normal method!")

    静态方法最大的优点是:不会绑定到实例对象上,换而言之就是节省开销。

     1 >>> c1 = C()
     2 >>> c2 = C()
     3 # 静态方法只在内存中生成一个,节省开销
     4 >>> c1.static is C.static
     5 True
     6 >>> c1.nostatic is C.nostatic
     7 False
     8 >>> c1.static
     9 <function C.static at 0x03001420>
    10 >>> c2.static
    11 <function C.static at 0x03001420>
    12 >>> C.static
    13 <function C.static at 0x03001420>
    14 # 普通方法每个实例对象都拥有独立的一个,开销较大
    15 >>> c1.nostatic
    16 <bound method C.nostatic of <__main__.C object at 0x03010590>>
    17 >>> c2.nostatic
    18 <bound method C.nostatic of <__main__.C object at 0x032809D0>>
    19 >>> C.nostatic
    20 <function C.nostatic at 0x0328D2B8>

    使用的时候需要注意的地方:静态方法并不需要 self 参数,因此即使是使用对象去访问,self 参数也不会传进去。

    1 >>> c1.static(1, 2, 3)
    2 1 2 3 6
    3 >>> C.static(1, 2, 3)
    4 1 2 3 6

    动动手部分:

    0. 定义一个类,当实例化该类的时候,自动判断传入了多少个参数,并显示出来。
    答:其实很容易啦,检查下大家之前的知识点有没有记牢固而已。

    1 class C:
    2         def __init__(self, *args):
    3                 if not args:
    4                         print("并没有传入参数")
    5                 else:
    6                         print("传入了 %d 个参数,分别是:" % len(args), end='')
    7                         for each in args:
    8                                 print(each, end=' ')

    1. 定义一个单词(Word)类继承自字符串,重写比较操作符(参考自学:Python 魔法方法详解),当两个 Word 类对象进行比较时,根据单词的长度来进行比较大小。
    加分要求:实例化时如果传入的是带空格的字符串,则取第一个空格前的单词作为参数。
    答:加分要求可以通过重载 __new__ 方法来实现(因为字符串是不可变类型),通过重写 __gt__、__lt__、__ge__、__le__ 方法来定义 Word 类在比较操作中的表现。
    注意,我们没有定义 __eq__ 和 __ne__ 方法。这是因为将会产生一些怪异不符合逻辑的结果(比如 Word('FishC') 会等于 Word('Apple'))
    代码清单:

     1 class Word(str):
     2 '''存储单词的类,定义比较单词的几种方法'''
     3     def __new__(cls, word):
     4         # 注意我们必须要用到 __new__ 方法,因为 str 是不可变类型
     5         # 所以我们必须在创建的时候将它初始化
     6         if ' ' in word:
     7             print "Value contains spaces. Truncating to first space."
     8             word = word[:word.index(' ')] #单词是第一个空格之前的所有字符
     9         return str.__new__(cls, word)
    10     def __gt__(self, other):
    11         return len(self) > len(other)
    12     def __lt__(self, other):
    13         return len(self) < len(other)
    14     def __ge__(self, other):
    15         return len(self) >= len(other)
    16     def __le__(self, other):
    17         return len(self) <= len(other)
  • 相关阅读:
    深入理解java虚拟机笔记线程安全与锁优化
    深入理解java虚拟机笔记(6)虚拟机字节码执行引擎2
    深入理解java虚拟机笔记java内存模式与线程1
    深入理解java虚拟机笔记(6)虚拟机字节码执行引擎1
    深入理解java虚拟机笔记java内存模式与线程4
    深入理解java虚拟机笔记(6)虚拟机字节码执行引擎3
    深入理解java虚拟机笔记java内存模式与线程2
    深入理解java虚拟机笔记线程安全与锁优化2
    深入理解java虚拟机笔记java内存模式与线程3
    聊天软件的后端架构NIO
  • 原文地址:https://www.cnblogs.com/luoxun/p/13574400.html
Copyright © 2020-2023  润新知