Properties 从数组创建python属性,共享getter和setter?

Properties 从数组创建python属性,共享getter和setter?,properties,python-3.6,Properties,Python 3.6,我一直在编写一个python脚本,每次更改某些值时,都应该修改一个并行值。例如: self.empire.gold = 345 self.empire.update_times.gold = time.time() 每次这样做都会让人感到痛苦,所以我一直在研究如何让这一切自动发生。这就是我想到的: import time class boring_object: pass class Object: def __init__(self, gold): s

我一直在编写一个python脚本,每次更改某些值时,都应该修改一个并行值。例如:

self.empire.gold = 345
self.empire.update_times.gold = time.time()
每次这样做都会让人感到痛苦,所以我一直在研究如何让这一切自动发生。这就是我想到的:

import time


class boring_object:
    pass


class Object:
    def __init__(self, gold):
        self._gold = gold
        self._updates = boring_object()

    @property
    def gold(self):
        return self._gold

    @gold.setter
    def gold(self, value):
        self._gold = value
        self._updates.gold = time.time()
使用这个,我可以自动更新时间

然而,我也希望将类似的setter应用于其他一些资源

我可以将此代码复制五次以覆盖
黄金
谷物
土豆
,等等,但我只想将一个资源名称数组传递给构造函数,并让它们共享通用的getter和setter。可能吗

在实现这些之前,我使用了一些更接近于
无聊的对象()

除了缺少属性功能之外,这也不能很好地
print()
。对于一个既可以使用通用的getter和setter,又可以在不需要太多额外代码的情况下很好地打印的解决方案来说,这是一个额外的好处


一旦我写了这篇文章,我发现了关于能手和二传手。一个答案是这样的,这将使我更接近我的目标,但我不想存储更新时间,也不想改变我最终在这个对象上设置的所有属性——只是初始化它时命名的属性。其他属性的行为应该像没有自定义的getter/setter逻辑一样。

\uuu getattr\uuuu
等等都是很好的神奇方法,可以让你变得聪明。然而,我建议你不要这样做。它们使您的代码难以理解和遵循。想象一下其他人(或一年后的你)试图理解。如果有一个明确的、易于理解的方法来完成工作,我总是希望这样

如果您想限制对属性的访问或向其添加一些小逻辑,比如存储更新时间,那么python
@属性
很好。然而,属性并不真正适合您的情况,因为您需要一些动态的东西,并且可以在运行时进行配置。那么为什么不使用显而易见的方法呢?一些“私人”字典(见下面的
\u财产
\u更新
)如何简单地存储帝国的资源

因此,以下是我对如何解决您的问题的建议:

import time


class Empire(object):

    def __init__(self, resources):
        self._possessions = {r: 0 for r in resources}
        self._updates = {r: None for r in resources}

    def update(self, resource, value):
        if resource not in self._possessions:
            raise ValueError('Your mighty Empire has no clue what {}'
                             ' really is and how to handle'
                             ' it.'.format(resource))
        self._possessions[resource] = value
        self._updates[resource] = time.time()

    def get(self, resource):
        if resource not in self._possessions:
            raise ValueError('Your poor empire has no {}.'.format(resource))
        return self._possessions[resource]


# Some use cases:
my_little_kingdom = Empire(('gold', 'celebrities', 'vanilla_ice'))

print(my_little_kingdom._updates['gold'])
my_little_kingdom.update('gold', 10)

print(my_little_kingdom.get('gold'))
print(my_little_kingdom._updates['gold'])

try:
    my_little_kingdom.update('bitcoin', 42)
except ValueError as e:
    print(e) 
如果坚持属性访问(第一次编辑) 顺便说一句,如果您真的非常想使用花哨的
\uuuu getattr\uuuuuu
\uuuu setattr\uuuuu
方法,您可以通过

def __getattr__(self, item):
    try:
        return self.get(item)
    except ValueError as e:
        # We are trying to get an attribute, so better
        # raise the corresponding error here.
        raise AttributeError(str(e))

def __setattr__(self, key, value):
    if key in ('_possessions', '_updates'):
        # We need to do this to avoid infinite loops.
        # You do see how quickly this gets really complicated!?
        return super().__setattr__(key, value)
    try:
        self.update(key, value)
    except ValueError as e:
        raise AttributeError(str(e))
\uuuu setattr\uuuu
的问题在这里变得非常明显。我们需要检查真实属性以避免无限循环。这样的东西会让你的代码非常复杂。无论如何,如果您将这两种神奇的方法添加到您的
帝国
,您现在就可以做到:

my_little_kingdom.gold = 123

print(my_little_kingdom.gold)
print(my_little_kingdom._updates['gold'])

try:
    my_little_kingdom.balloons = 99
except AttributeError as e:
    print(e)
奖励积分:可打印帝国(第二次编辑) 当然,要打造一个可打印的帝国,只需添加以下方法:

def __str__(self):
    possessions = ', '.join('{value} {key}'.format(value=p[1],
                                                   key=p[0])
                            for p in self._possessions.items())
    return ('A glorious and filthy rich empire ' 
            'owning {}.'.format(possessions))
现在你可以通过

print(my_little_kingdom)
要了解这一点:


一个拥有123黄金、0名人、0香草冰淇淋的光荣而肮脏的帝国。

我同意Smcatepillar,只要您不需要在运行时添加新资源(如黄金、白银等),我就避免使用
(g | s)Ettr_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,我不明白?只要对你的
\uuuu getattr\uuuuu
\uuu setattr\uuuuuuu
进行保护,只接受你初始化对象时使用的值。@AChampion和其他属性的行为就好像没有自定义的
\uuu getattr\uuuuuu
\uuuu setattr\uuuuuuu
一样。是的,它非常复杂,这就是我在这里问的原因。我不明白你的代码是如何处理真实属性的。
\uuuu getattr\uuuu
\uuuu setattr\uuuuu
之间的区别在于,只有当你想要的属性不是真实属性时才会调用
\uu getattr\uuuuu
。但是,如果您执行类似于
foo.bar=42
的操作,则始终会调用
\uuuuuu setattr\uuuuuuuuuu
。所以我们需要检查
是否输入(“'u财产','u更新')
,否则即使调用
帝国的构造函数也会导致无限循环。为什么?因为第一个语句
self.\u ownections={…}
将调用
\uuu setattr\uuuu
,后者随后将调用
update
update
依次使用
self.\u Occupations[…]=…
,这将使您返回到
\uuuuuuuSetAttr\uuuuuuuAttr
等等。我想使用属性,因为我想循环查看属性名称列表并使用setattr为什么要循环查看属性?这将涉及使用并可能实现
\uuuuu dir\uuuu
。你的项目将变得很难理解。为什么不按照我的回答直接使用字典来存储资源呢?为什么你需要一个简单问题的复杂解决方案?
print(my_little_kingdom)