Skip to content

FAQs for Lab 1

FrightenedFox edited this page Mar 25, 2022 · 3 revisions

Lab 1 常见问题汇总

环境配置:Jupyter-notebook Bad file descriptor 错误

这个问题一般情况下是由 pyzmq 版本过高引起的。如果您的 Python 版本为 3.9.x 及以下,应该可以使用将 pyzmq 降级到 19.0.2 的方式解决问题;如果降级之后还不能成功,可以尝试将 Pillow 降级到 8.2.0;如果您的 Python 版本为 3.10.x 及以上,在降级 pyzmq 时应该会报两百多行的错误然后失败。这是因为 pyzmq 19.0.2 存在对 Windows 平台的适配问题。参考 pyzmq 官网上对 version 21.0 更新的说明:

Missing MSVCP140.dll in Python 3.9 wheels on Windows, causing vcruntime-redist package to be required to use the Python 3.9 wheels for pyzmq 20.0

但是,21.0 也是不行的,因为它需要 Microsoft Visual C++ 14.0 以上版本的编译器……

所以这种情况下,建议的方式是使用 anaconda 或 miniconda,直接使用我们给出的 Windows-Env.yml 进行安装,命令为:

conda env create --file 到……的路径\Windows-Env.yml --name 环境名称

然后直接使用此虚拟环境中 Python 3.7.2 的内核进行实验。此虚拟环境中同时配置了以后的实验所需的包,应可用于以后所有实验。

关于异常处理:如何抛出异常?

在 Python 中,raise 语句专门用于抛出异常(exception)。异常的意思是,程序遇到了设计者不愿意看到的情况,例如在 Rational 类初始化的时候分母为 0,就应该抛出一个 ZeroDevisionError,以提醒调用者这里出现了除零异常。如果要捕获这个异常,可以使用 try except finally 语句,例如:

def raiseError():
    raise NotImplementedError("This function shouldn't be called!")

if __name__ == "__main__":
    try:
        raiseError()
    except NotImplementedError:
        print("An exception flew by!")
    finally:
        print("This will always be printed")

关于异常和异常处理的更多信息,可以参考 Built-in Exceptions

关于运算符重载:__add__ 方法是个啥?

运算符重载就是指,当我对一个类进行加减乘除等操作时,我要进行一些特殊处理。在 Python 的内置类型中可以看到这样的例子,整数加法返回整数,字符串加法返回连接后的字符串,显然,这个 + 符号带有一词多义的特性。当我们使用 a + b 时,事实上它调用了一个方法 __add__,请看以下代码:

i = 3
i = i.__add__(4)
print(i)

这里的输出结果是 7,正是 3 + 4 运算的结果。这意味着,当我执行 i + 4 的求值时,其求值过程就是 i.__add__(4),这是运算符重载的基本原理。

重载(override)是指,当一个新的类继承自原先的类时,我们使用同名函数代替原先类中的同名函数。这样,在新的类调用这个函数时,它就不会调用其父类的同名函数。因此,只需要重载 __add__ 函数,即可实现自定义类的加法。关于各个运算符对应的方法,可以参考 Operators

关于 __eq__ 方法和等于判断

在后面的要求中,我们要求实现判断语句。在实现 == 的过程中,可能会发现,调用 == 并不会报 NotImplementedError 。原因是任何一个类都继承了一个叫做 type 的基类,其中自带有 __eq__ 方法,这个方法对于任何两个不同的实例都会返回 False。而在原始版本的 Number 类中事实上已经重载了 __eq__,为了降低难度删去但未删去相关的要求,于是造成了一些混乱。解决的方法就是,在 Rational 类中自己定义 __eq__ 方法,也可以选择在 Number 类中加上对应的 NotImplementedError

关于 __repr____str__

当调用 print 函数时,会调用 __str__ 方法,并输出返回值字符串。这是对 __str__ 方法的最简单理解。因此,如果对于分母为 1 直接以整数方式输出分子,可以修改原有的 __repr____str__ 方法。

关于 NaN 等类的实现

这部分确实超出了我们所提供的内容的范畴。有兴趣的同学可以参考 Data Model 中对类生成的描述,重载 __new__ 方法来尝试实现。例如,我们以 NaN 为例,在 Rational 类中应该如此定义:

class Rational:
    ...

    def __init__(self, p, q):
        if p == 0:
            self.q = 1
        self._simplify()

    def __new__(cls, p, q):
        obj = object.__new__(cls)
        obj.p = p
        obj.q = q
        if p == 0 and q == 0:
            return NaN()
        return obj

    ...

这样,当 pq 都为 0 时,构造 Rational(0, 0) 将返回一个 NaN 类的实例。