实例变量的Pythonic别名?

2 投票
3 回答
4408 浏览
提问于 2025-04-17 10:56

我有一个类,用来存储数据在一个列表里,主要是为了继承的需要。我想知道,除了创建获取和设置函数(也就是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 个回答

0

如果你只是想让访问 ident 的代码变得更简短,你可以用“老式”的方法来使用“属性”。也就是说,你可以把获取和设置的函数作为参数传给它,而不是用装饰器的方式。

在这种情况下,这些函数很简单,可以用 lambda 函数来写,这样不会影响代码的可读性。

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

在编程中,有时候我们会遇到一些问题,尤其是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,不知道该如何解决。比如,有人可能在使用某个特定的功能时,发现它并没有按照预期工作,或者出现了错误信息。这种情况下,通常我们可以在网上寻找答案,比如在StackOverflow这样的平台上。

在这些平台上,很多人会分享他们遇到的问题和解决方案。你可以看到其他程序员是如何解决类似的问题,或者他们是如何理解某个概念的。这对于刚开始学习编程的人来说,特别有帮助,因为你可以从别人的经验中学习,避免走弯路。

总之,遇到问题时,不要害怕去寻求帮助。网络上有很多资源可以帮助你理解和解决问题,记得多多利用这些资源哦!

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')
3

如果你把你的值或者属性存储在一个字典里,效果会更好:

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

撰写回答