0

How can I use the get descriptor to output values of list elements?

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])

Output:

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

Desired Output:

1
2
3
Jonathan Koren
  • 883
  • 7
  • 9

1 Answers1

2

This snippet could bring you closer, but it's not the same. Z subclasses a list and defines __get__ for acting as a descriptor.

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()

Using _LiteralForContainerDescriptorZ is optional, it gives a bit nicer syntax.

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__))

Calling it, the prints are:

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