Why can't `round` be defined for non-floats?

2019-01-28 23:05发布

Given a simple class like

class Vector(object):
    def __init__(self, value):
        self.value = value
    def __abs__(self):
        return math.sqrt(sum([x**2 for x in self.value]))
    def __round__(self, *n):
        return [round(x,*n) for x in self.value]

why does abs(Vector([-3,4])) correctly yield 5 while round(Vector([-3.1,4])) complains with a TypeError: a float is required instead of the desired [-3,4], and how can this be fixed?

I know round should usually return a float, but for a vector as in this example there is probably no ambiguity on the possible meaning, so why can this not be simply overridden? Do I really have to subclass numbers.Real, or define Vector(...).round(n) instead?

1条回答
仙女界的扛把子
2楼-- · 2019-01-28 23:36

The __round__ special method was only introduced in Python 3. There is no support for the special method in Python 2.

You'll have to use a dedicated method instead of the function:

class Vector(object):
    def __init__(self, value):
        self.value = value

    def round(self, n):
        return [round(x, n) for x in self.value]

or you'd have to provide your own round() function:

import __builtin__

def round(number, digits=0):
    try:
        return number.__round__(digits)
    except AttributeError:
        return __builtin__.round(number, digits)

You could even monkey-patch this into the __builtins__ namespace:

import __builtin__

_bltin_round = __builtin__.round

def round(number, digits=0):
    try:
        hook = number.__round__
    except AttributeError:
        return _bltin_round(number, digits)
    else:
        # Call hook outside the exception handler so an AttributeError 
        # thrown by its implementation is not masked
        return hook(digits)

__builtin__.round = round
查看更多
登录 后发表回答