Есть ли хитрость, чтобы «перегрузить оператор точки»? - PullRequest
16 голосов
/ 01 апреля 2011

Я знаю, что вопрос немного странно сформулирован, но я не могу придумать другого способа сказать это. У меня есть приложение, которое работает с большими объектами json, и я хочу просто сказать:

object1.value.size.whatever.attributexyz

вместо

object1.get('value').get('size').get('whatever').get('attributexyz')

Есть ли какой-нибудь умный способ поймать AttributeError, который будет поднят, и проверить внутри структуры данных, соответствует ли этот атрибут какому-либо из его значений?

Ответы [ 3 ]

25 голосов
/ 01 апреля 2011

В object1 определения класса,

def __getattr__(self, key):
    return self.get(key)

Любая попытка разрешить имя свойства, метода или поля, которое фактически не существует в самом объекте, будет передана в __getattr__.

Если у вас нет доступа к определению класса, то есть это что-то вроде словаря, оберните его в классе. Для словаря вы можете сделать что-то вроде:

class DictWrapper(object):
    def __init__(self, d):
        self.d = d
    def __getattr__(self, key):
        return self.d[key]

Обратите внимание, что KeyError будет вызываться, если ключ недействителен; соглашение, однако, должно вызвать AttributeError (спасибо, С. Лотт!). Вы можете повторно вызвать KeyError как AttributeError, например, при необходимости:

try:
    return self.get(key)
except KeyError as e:
    raise AttributeError(e)

Также помните, что если объекты, которые вы возвращаете из __getattr__, также являются, например, словарями, вам нужно будет также обернуть их.

1 голос
/ 01 апреля 2011

Обернуть структуру в объект с помощью определенного метода __getattr__().Если у вас есть контроль над структурой, вы можете определить ее __getattr___().Getattr делает то, что вы хотите - «ловит» недостающие атрибуты и, возможно, возвращает какое-то значение.

0 голосов
/ 20 ноября 2017

Просто дополнить приведенные выше ответы примером.

class A:
    def __init__(self, *args):
        self.args = args

    def dump(self, *args):
        print(self.args, args)
        return self.args, args

class Wrap:
    def __init__(self, c, init_args):
        self.c, self.init_args = c, init_args

    def __getattr__(self, key):
        inst = self.c(*self.init_args)
        return getattr(inst, key)

a = Wrap(A, (1, 2, 3))
a.dump(4, 5, 6)

b = Wrap(dict, ({1:2},))
print(b.get(1), b.get(3))

# This will fail                                                                                                                                                                                                                                  
print(b[1])

выходы,

$ python --version
Python 3.6.3
$ python wrap.py 
(1, 2, 3) (4, 5, 6)
2 None
Traceback (most recent call last):
  File "wrap.py", line 24, in <module>
    print(b[1])
TypeError: 'Wrap' object does not support indexing
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...