为什么你不能将魔术方法定义为与内置方法完全相同?

时间:2017-01-17 02:36:19

标签: python python-3.x

我正在创建一个irc bot,并且大量的脚本会将符合f'{label}: {value}'格式的内容返回。所以我创建了一个Result类并给它__bytes__方法,因为我以前使用它并且它工作正常。或者我认为......

WHITE = '00'
BLACK = '01'
DARK_BLUE = '02'
DARK_GREEN = '03'
RED = '04'
DARK_RED = '05'
PURPLE = '06'
ORANGE = '07'
YELLOW = '08'
GREEN = '09'
TEAL = '10'
CYAN = '11'
BLUE = '12'
PINK = '13'
GREY = GRAY = '14'

def colorize(msg, color):
  """Add color code to message"""
  return f'{color}{msg}'

class Result:

  def __init__(self, label, value, color=RED):
    self.repr = f'{colorize(label, color)}: {value}'

  def __bytes__(self, encoding='utf-8'):
    return self.repr.encode(encoding)

def join_results(results, sep=' '):
  """Break results into a maximum of 350 bytes per line"""
  sep = sep.encode() if isinstance(sep, str) else sep
  if not isinstance(sep, bytes):
    raise TypeError('sep must be bytes or str')
  if (not isinstance(results, list)) or (not results):
    return []
  seplen = len(sep)
  x = bytes(results[0], encoding='utf-8')
  ret = []
  for result in results[1:]:
    y = bytes(result)
    msglen = len(y) + len(x)
    if (msglen + seplen) > 350:
      ret.append(x.decode())
      x = y
    else:
      x = sep.join((x, y))
  return ret + [x.decode()]  

在上面的代码中,调用Result上的字节会引发类型错误:

>>> bytes(r, encoding='utf-8')
Traceback (most recent call last):
  File "<pyshell#265>", line 1, in <module>
    bytes(r, encoding='utf-8')
TypeError: encoding without a string argument   

有些情况下,我希望join_results也可以处理字符串列表。将join_results中的x更改为x = bytes(str(results[0]), encoding='utf-8')而不是x = bytes(results[0], encoding='utf-8')很简单,但为什么呢?然后我将不得不将__str__添加到Result并浪费cpu时间将任何参数转换为x字符串。

我还检查了其他内容,例如__int__,其内置函数也接受base参数将字符串转换为int。但与__bytes__一样,它也会抛出TypeError: int() can't convert non-string with explicit base。错误消息是明确的,所以要重申:我不是在问为什么它会抛出错误。我问的是,为了使__str____bytes____int__之类的东西像内置函数那样工作,被迫跳过箍的逻辑是什么。

1 个答案:

答案 0 :(得分:1)

如果我理解正确,则会遇到bytes encoding bytes不能作为身份功能使用的问题。

您认为您被迫将str转换为coerce_to_bytes = lambda x: x if isinstance(x, bytes) else bytes(x, encoding='utf-8') s = "foo" b = b"bar" print(coerce_to_bytes(s), coerce_to_bytes(b)) >>> b'foo' b'bar' 只是为了重新编码,但事实并非如此。您只需要尝试编码字节。

你可以通过编写一个小帮助函数来解决它,它可以扩展功能以满足你的需求:

{{1}}

这正是您所期望的。至少对于字节和字符串。我想如果你需要处理所有类型,那么逻辑会有点复杂,但不是那么多。