Разбор дампа Википедии

Например, используя этот дамп Википедии:

http: //en.wikipedia.org/w/api. Примечательно, что если я использую класс «старого стиля» (не наследую от объекта), я могу сделать это довольно просто, определив метод __ coerce __ , но классы старого стиля устарели и будут удалены в python3.

Когда я делаю то же самое с классом нового стиля, я получаю эту ошибку:

TypeError: unsupported operand type(s) for /: 'Castable' and 'int'

Я верю, что это по замыслу, но тогда как я могу смоделировать старый стиль __ coerce __ поведение с классом нового стиля? Вы можете найти мое текущее решение ниже, но оно довольно уродливое и многословное.

Это соответствующая документация: (я думаю)

Бонусные баллы:

    print pow(c, 2, 100)

8
задан bukzor 20 August 2010 в 20:19
поделиться

4 ответа

Это работает, и является менее грубым после нескольких улучшений (реквизит для @jchl), но все же кажется, что это должно быть ненужным, особенно учитывая, что вы получаете это бесплатно с классами «старого стиля».

Я все еще ищу лучший ответ. Если нет лучшего метода, это кажется мне регрессией в языке Python.

def ops_list():
    "calculate the list of overloadable operators"
    #<type 'object'> has functions but no operations
    not_ops = dir(object)

    #calculate the list of operation names
    ops = set()
    for mytype in (int, float, str):
        for op in dir(mytype):
            if op.endswith("__") and op not in not_ops:
                ops.add(op)
    return sorted(ops)

class MetaCastable(type):
    __ops = ops_list()

    def __new__(mcs, name, bases, dict):
        #pass any undefined ops to self.__op__
        def add_op(op):
            if op in dict:
                return
            fn = lambda self, *args: self.__op__(op, args)
            fn.__name__ = op
            dict[op] = fn

        for op in mcs.__ops:
            add_op( op )
        return type.__new__(mcs, name, bases, dict)


class Castable(object):
    __metaclass__ = MetaCastable
    def __str__(self):
        print "str!"
        return "<Castable>"
    def __int__(self):
        print "int!"
        return 42
    def __float__(self):
        print "float!"
        return 2.718281828459045

    def __op__(self, op, args):
        try:
            other = args[0]
        except IndexError:
            other = None
        print "%s %s %s" % (self, op, other)
        self, other = coerce(self, other)
        return getattr(self, op)(*args)

    def __coerce__(self, other):
        print "coercing like %r!" % other
        if other is None: other = 0.0
        return (type(other)(self), other)
5
ответ дан 5 December 2019 в 10:38
поделиться

Вам необходимо определить __ div __ , если вы хотите, чтобы c / 3 работал. Python не будет сначала преобразовывать ваш объект в число за вас.

8
ответ дан 5 December 2019 в 10:38
поделиться
class Castable(object):
    def __div__(self, other):
        return 42 / other
0
ответ дан 5 December 2019 в 10:38
поделиться
class MetaCastable(type):
    __binary_ops = ( 
            'add', 'sub', 'mul', 'floordiv', 'mod', 'divmod', 'pow', 'lshift', 
            'rshift', 'and', 'xor', 'or', 'div', 'truediv',
    )

    __unary_ops = ( 'neg', 'pos', 'abs', 'invert', )

    def __new__(mcs, name, bases, dict):
        def make_binary_op(op):
            fn = lambda self, other: self.__op__(op, other)
            fn.__name__ = op
            return fn

        for opname in mcs.__binary_ops:
            for op in ( '__%s__', '__r%s__' ):
                op %= opname
                if op in dict:
                    continue
                dict[op] = make_binary_op(op)

        def make_unary_op(op):
            fn = lambda self: self.__op__(op, None)
            fn.__name__ = op
            return fn

        for opname in mcs.__unary_ops:
            op = '__%s__' % opname
            if op in dict:
                continue
            dict[op] = make_unary_op(op)

        return type.__new__(mcs, name, bases, dict)

class Castable(object):
    __metaclass__ = MetaCastable
    def __str__(self):
        print "str!"
        return "<Castable>"
    def __int__(self):
        print "int!"
        return 42
    def __float__(self):
        print "float!"
        return 2.718281828459045

    def __op__(self, op, other):
        if other is None:
            print "%s(%s)" % (op, self)
            self, other = coerce(self, 0.0)
            return getattr(self, op)()
        else:
            print "%s %s %s" % (self, op, other)
            self, other = coerce(self, other)
            return getattr(self, op)(other)

    def __coerce__(self, other):
        print "coercing like %r!" % other
        return (type(other)(self), other)
3
ответ дан 5 December 2019 в 10:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: