【问题标题】:Counting used attributes at runtime在运行时计算使用的属性
【发布时间】:2018-12-12 04:59:21
【问题描述】:

我正在开发一个 python 项目,该项目需要我将某些对象的某些属性编译到数据集中。我目前使用的代码如下:

class VectorBuilder(object):
    SIZE = 5

    def __init__(self, player, frame_data):
        self.player = player
        self.fd = frame_data

    def build(self):
        self._vector = []

        self._add(self.player)
        self._add(self.fd.getSomeData())
        self._add(self.fd.getSomeOtherData())

        char = self.fd.getCharacter()
        self._add(char.getCharacterData())
        self._add(char.getMoreCharacterData())

        assert len(self._vector) == self.SIZE
        return self._vector

    def _add(self, element):
        self._vector.append(element)

但是,此代码有点不干净,因为向数据集添加/删除属性还需要正确调整 SIZE 变量。我什至有SIZE 变量的原因是,在创建数据集本身之前,需要在运行时知道数据集的大小。

我考虑过将用于构建数据集的所有函数的列表保留为字符串(如在attributes = ['getPlayer', 'fd.getSomeData', ...] 中),然后将build 函数定义为:

def build(self):
    self._vector = []
    for att in attributes:
        self._vector.append(getattr(self, att)())
    return self._vector

这将使我可以简单地访问大小len(attributes),并且我只需要编辑attributes,但我不知道如何使这种方法与链式函数调用一起使用,例如self.fd.getCharacter().getCharacterData()

有没有更简洁的方法来完成我想做的事情?

编辑:

一些额外的信息和澄清是必要的。

  1. 我使用__ 是因为我在网上阅读了一些不好的建议(本质上是说我应该对模块私有成员使用_,对类私有成员使用__)。我现在已将它们编辑为 _ 属性。
  2. getter 是我正在使用的框架的一部分。
  3. 向量存储为私有类成员,因此我不必将其传递给构造方法,实际上这些方法比简单的_add 更多,还可以做一些其他的事情,例如规范化和bool->int 转换在将元素添加到向量之前对其进行处理。
  4. SIZE 就目前而言,是一个真正的常数。它只在VectorBuilder 的第一行被赋予一个值,并且在运行时从不改变。我意识到我没有在主帖中正确地澄清这一点,但新属性永远不会在运行时添加。我所说的调整将在编程时进行。例如,如果我想添加一个新属性,我需要在build函数中添加它,例如:

    self._add(self.fd.getCharacter().getAction().getActionData().getSpeed())
    

    ,以及将SIZE 定义更改为SIZE = 6

  5. 这些属性被编译成一个简单的 Python 列表(但可能会被一个 numpy 数组替换),然后作为输入向量传递给神经网络。但是,需要首先构建神经网络本身,这发生在任何数据可用之前(即在创建任何输入向量之前)。不过,为了成功构建,神经网络需要知道它将接收的输入向量的大小。这就是为什么 SIZE 是必要的,也是 assert 声明的原因 - 确定我传递给网络的向量实际上是我声称要传递给它的大小。

我知道代码是非 Python 的,这就是我在这里的原因 - 代码有效,只是丑陋。

【问题讨论】:

  • 你为什么使用__属性?为什么要将值存储在列表中,而不是作为普通属性存储,或者至少存储在字典中?为什么你首先想要像getCharacter() 这样的吸气剂?为什么当你唯一一次访问向量时,它会存储在任何地方,而是用你立即返回的全新值替换它? assert 实际上是为了防止什么?您尝试做的每件事似乎都过于复杂且不符合标准,而且在不知道原因的情况下,很难说其中的某个特定元素是否特别过于复杂
  • 按照约定,属性名称全为大写字母,如SIZE,表示它是一个永远不会更改的常量值,但您提到“调整SIZE 变量”。如果您要编写 Python 代码,我强烈建议您阅读(并关注)PEP 8 - Style Guide for Python Code** 建议。最后,正如@abarnert 所说,去掉属性名称上的__ 前缀,只需一个简单的_ 来表示某些东西是私有的就足够了。
  • @martineau 我认为这意味着SIZE 应该在类创建时创建(可能是通过一些模块级代码,因为我怀疑他会为此使用元类......但你永远不知道......)然后永远不会改变。如果是这样,它实际上是一个常数。例如,如果他使用普通的__slots__ 类,他可以编写一个设置cls.SIZE = len(cls.__slots__) 的简单装饰器,即使从技术上讲,它是在type 调用返回后分配的,你仍然可以称其为常量,对吧?
  • 我已编辑 OP 以尝试回答上述 cmets 中提出的问题。

标签: python python-3.x dynamic attributes getattr


【解决方案1】:

除了提供属性的字符串作为您希望从中创建输入参数的列表之外,为什么不使用包含所有 的列表来初始化 build 函数>值由您的 getter 函数返回?

然后,您的 SIZE 变量仍将是 build(self,*args) 中提供的动态参数列表的长度。

【讨论】:

  • 我需要 SIZE 才能访问这些值。
  • 好的。但在您选择输入变量的同时,您应该可以访问SIZE。你的方法对我来说似乎有点复杂。
猜你喜欢
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多