导航

python-魔法函数-__str__ __repr__ 的一次异常

Posted on 2022-08-26 18:05  old_dog~  阅读(101)  评论(0)    收藏  举报
# encoding: utf-8
import logging

ERROR_NOT_FOUNDED_FILE = "error_not_founded_file"


class GeneralError(Exception):


def __init__(self, value, description):
print("GeneralError __init__")
self.value = value
self.description = description

def __repr__(self):
print("__repr__")
return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)

def __str__(self):
print("__str__")
return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)


class FileError(GeneralError):

def __init__(self, description):
super(FileError, self).__init__(ERROR_NOT_FOUNDED_FILE, description)

def __repr__(self):
return super(FileError, self).__repr__() # 不规范

def __str__(self):
super(FileError, self).__str__() # 会报错


try:
raise FileError('file error')
except Exception as e:
logging.info(f"exec error: {e}")
print("补救措施!")

 执行结果如下:

 

 

 错误:
__str__ returned non-string (type NoneType) 可以看出,e返回了None。

debug:

    def __str__(self):
        super(FileError, self).__str__()  # 调用了,父类的__str__函数,没有返回(也可以理解为返回了None)。
logging.info(f"exec error: {e}")  # 调用了FileError().__str__,没有返回值,自然就报错了。

修复:

def __str__(self):
        return super(FileError, self).__str__()  # 调用了,父类的__str__函数,返回执行结果。

或者
不实现重写__str__。

那么正常的代码应该是:

# encoding: utf-8

import logging

ERROR_NOT_FOUNDED_FILE = "error_not_founded_file"


class GeneralError(Exception):

def __new__(cls, *args, **kwargs):
print("GeneralError __new__")
return super(GeneralError, cls).__new__(cls)

def __init__(self, value, description):
print("GeneralError __init__")
self.value = value
self.description = description

def __repr__(self):
print("__repr__")
return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)

def __str__(self):
print("__str__")
return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)


class FileError(GeneralError):

def __init__(self, description):
super(FileError, self).__init__(ERROR_NOT_FOUNDED_FILE, description)

def __repr__(self):
return super(FileError, self).__repr__()

  # 我选择不重写!!! 唯一的修改
# def __str__(self):
# super(FileError, self).__str__()


try:
raise FileError('file error')
except Exception as e:
logging.info(f"exec error: {e}")
print("补救措施!")

当然,这个环境里,代码能跑了。不过,能跑是能跑,有一处不规范

def __repr__(self):
print("__repr__")
return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)

官方文档对于__repr__的解释是(repr会调用对象的__repr__):

def repr(obj): # real signature unknown; restored from __doc__
    """
    Return the canonical string representation of the object.
    
    For many object types, including most builtins, eval(repr(obj)) == obj.
    """
    pass

很显然:

err = FileError("file  error")
eval(repr(err)) == err

  File "E:/coding/hello.py", line 53, in <module>
    eval(repr(err)) == err
  File "<string>", line 1
    <FileError error_not_founded_file:file  error>
    ^
SyntaxError: invalid syntax

所以,要修改代码为:

    def __repr__(self):
        print("__repr__")
        return "{}('{}')".format(self.__class__.__name__, self.description)

那么,最终的代码应该是:

# encoding: utf-8

import logging

ERROR_NOT_FOUNDED_FILE = "error_not_founded_file"


class GeneralError(Exception):

    def __new__(cls, *args, **kwargs):
        print("GeneralError  __new__")
        return super(GeneralError, cls).__new__(cls)

    def __init__(self, value, description):
        print("GeneralError __init__")
        self.value = value
        self.description = description

    def __repr__(self):
        print("__repr__")
        return "{}('{}')".format(self.__class__.__name__, self.description)  # 第一处修改: 返回字符串格式修改 

    def __str__(self):
        print("__str__")
        return "<{} {}:{}>".format(self.__class__.__name__, self.value, self.description)


class FileError(GeneralError):

    def __init__(self, description):
        super(FileError, self).__init__(ERROR_NOT_FOUNDED_FILE, description)
   
# 第二处修改:不重写父类方法
# def __repr__(self): # return super(FileError, self).__repr__() # def __str__(self): # super(FileError, self).__str__() try: raise FileError('file error') except Exception as e: logging.info(f"exec error: {e}") print("补救措施!") err = FileError("file error") eval(repr(err)) == err