Pythonic псевдоним для переменной экземпляра? - PullRequest
2 голосов
/ 24 января 2012

У меня есть класс, в котором я храню данные в списке по причинам наследования. Я хотел бы знать, и я сделал свою долю в поиске Google, есть ли более чистый способ, кроме создания функций и свойств getter / setter, чтобы дать псевдоним элементу в этом списке?

Например ...

class Serializable(object):
    """Adds serialization to from binary string"""

    def encode(self):
        """Pack into struct"""
        return self.encoder.pack(*self)

    def decode(self, data_str):
        """Unpack from struct"""
        self.data = self.encoder.unpack(data_str)
        return self.data


class Ping(Serializable):

    encoder = Struct("!16sBBBL")

    def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
        self.data = [ident, 1, ttl, hops, length]
        self.ident = property(self.data[0])

    def __getitem__(self, index):
        return self.data[index]

    @property
    def ident(self):
        return self.data[0]

    @ident.setter
    def ident(self, value):
        self.data[0] = value

    @property
    def protocol(self):
        return self.data[1]

    @protocol.setter
    def protocol(self, protocol):
        self.data[1]

Я бы предпочел более компактное решение для ссылки на object.ident, сохраняя при этом возможность упаковки и распаковки, как указано выше.

Ответы [ 3 ]

3 голосов
/ 24 января 2012

Если вы храните ваши значения / свойства в словаре вместо:

def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
    self.data = {
        'ident': ident,
        'protocol': 1,
        'ttl': hops,
        'length': length,
    }

А затем переопределить __getattr__ и __setattr__:

def __getattr__(self, attr):
    return self.data[attr]
def __setattr__(self, attr, value):
    if attr == 'data':
        object.__setattr__(self, attr, value)
    else:
        self.data[attr] = value

Теперь вы можете сделать это:

>>> ping = Ping()
>>> ping.protocol
1
>>> ping.protocol = 2
>>> ping.protocol
2

Если self.data обязательно должен быть списком, вы можете сделать это вместо этого:

class Ping(Serializable):

    mapping = ('ident', 'protocol', 'ttl', 'hops', 'length')

    encoder = Struct("!16sBBBL")

    def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
        self.data = [ident, 1, ttl, hops, length]

    def __getitem__(self, index):
        return self.data[index]

    def __getattr__(self, attr):
        index = self.mapping.index(attr)
        return self.data[index]

    def __setattr__(self, attr, value):
        if attr == 'data':
            object.__setattr__(self, attr, value)
        else:
            index = self.mapping.index(attr)
            self.data[index] = value
2 голосов
/ 16 декабря 2014
def alias_property(key):
    return property(
        lambda self: getattr(self, key),
        lambda self, val: setattr(self, key, val),
        lambda self: delattr(self, key))

class A(object):

    def __init__(self, prop):
        self.prop = prop

    prop_alias = alias_property('prop')
0 голосов
/ 24 января 2012

Если ваша проблема заключается только в сокращении кода для доступа к ident, вы можете просто использовать «свойство» в «старом стиле» - то есть вы передаете ему в качестве параметров функции получения и установки вместоиспользуя его в качестве декоратора.

В этом случае функции настолько малы, что могут быть лямбда-функциями, не влияя на читаемость кода.

class Ping(Serializable):

    encoder = Struct("!16sBBBL")

    def __init__(self, ident=None, ttl=TTL, hops=0, length=0):
        if ident is None:
            ident = create_id()
        self.data = [ident, 1, ttl, hops, length]
        # The line bellow looks like garbage -
        # it does not even make sense as a call to `property`
        # should have a callable as first parameter
        # returns an object that is designed to work as a class attribute
        # self.ident = property(self.data[0])
        # rather:
        self.ident = ident 
        # this will use the property defined bellow

    def __getitem__(self, index):
        return self.data[index]

    ident = property(lambda s: s.data[0], lambda s, v: s.data[0].__setitem__(0, v)
    protocol = property(lambda s: s.data[1], lambda s, v: s.data[1].__setitem__(1, v)
...