Как использовать дескриптор python __get__ для вывода значений элементов списка? - PullRequest
0 голосов
/ 26 мая 2020

Как я могу использовать дескриптор get для вывода значений элементов списка?

class X(object):
  def __init__(self,value):
    self.value = value
  def __get__(self,obj,objtype):
    return self.value

class Y(object):
  a = X(1)
  b = X(2)
  c = [X(3),X(4)]

y = Y()
print(y.a)
print(y.b)
print(y.c[0])

Вывод:

1
2
<__main__.X object at ...>

Желаемый результат:

1
2
3

1 Ответ

2 голосов
/ 26 мая 2020

Этот фрагмент может приблизить вас, но это не то же самое. Z подклассы a list и определяет __get__ для работы в качестве дескриптора.

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

    def __get__(self, obj, objtype):
        return self.value

    def __repr__(self):
        return "X(%r)" % self.value

class Z(list):
    def __get__(self, obj, objtype):
        return self

    def __getitem__(self, index):
        """override brackets operator, suggested by Azat Ibrakov"""
        list_item = super(Z, self).__getitem__(index)
        try:
            return list_item.value
        except AttributeError:
            return list_item

class _LiteralForContainerDescriptorZ(object):
    def __getitem__(self, keys):
        """override brackets operator, basing on https://stackoverflow.com/a/37259917/2823074"""
        if not isinstance(keys, tuple):
            keys = (keys,)
        assert not any(isinstance(key, slice) for key in keys)  # avoid e.g. ZL[11:value, key:23, key2:value2]
        return Z(keys)


ZL = _LiteralForContainerDescriptorZ()

Использование _LiteralForContainerDescriptorZ необязательно, это дает немного более приятный синтаксис.

class Y(object):
    a = X(1)
    b = X(2)
    c = Z([X(3.14), X(4)]) # define 'c' using constructor of Z class inherited from list
    d = ZL[X(3.14), X(4)]  # define 'd' using custom literal


y = Y()

for statement_to_print in [
    "y.a", "y.b", "y.c","y.d", "y.c[0]", "y.c[1]", "y.d[0]",
]:
    value = eval(statement_to_print)
    print("{st:9} = {ev:<16}   # type: {tp}".format(
        st=statement_to_print, ev=value, tp=type(value).__name__))

Вызывая его, распечатки:

y.a       = 1                  # type: int
y.b       = 2                  # type: int
y.c       = [X(3.14), X(4)]    # type: Z
y.d       = [X(3.14), X(4)]    # type: Z
y.c[0]    = 3.14               # type: float
y.c[1]    = 4                  # type: int
y.d[0]    = 3.14               # type: float
...