从对象获取属性的 Pythonic 方式是什么?

What is the Pythonic way of getting attributes from objects?

我有一个代表 Atom 的 class,它有两组坐标,其中一组是笛卡尔坐标,我想遵循最佳架构实践从 class.

以前我创建了多个 class 方法来获取不同类型的属性,但我觉得这不是 pythonic,并且不必要地使我的代码混乱,但是我不确定通常的解决方案是什么.

因为它可能会帮助别人回答,请参阅下面的 Atom class:

class Atom():

    def __init__(self, element, x_coord, y_coord, z_coord):
        '''
        Instantiate new atom object.
        '''
        #Check information is correct
        if not isinstance(element, str):
            raise ValueError('Element must be a string.')
        if not isinstance(x_coord, int) and not isinstance(x_coord, float):
            raise ValueError('All coordinates must be numeric, x is not.')
        if not isinstance(y_coord, int) and not isinstance(y_coord, float):
            raise ValueError('All coordinates must be numeric, y is not.')
        if not isinstance(z_coord, int) and not isinstance(z_coord, float):
            raise ValueError('All coordinates must be numeric, z is not.')
        self.coordinates = np.array([x_coord, y_coord, z_coord]).astype(float)
        self.cartesian = None
        self.element = element

    def __repr__(self):
        '''
        Atom representation.
        '''
        x, y, z = list(self.coordinates)
        return f"Atom('{self.element}', {x}, {y}, {z})"

    def __copy__(self):
        x, y, z = [float(x) for x in list(self.coordinates)]
        return Atom(self.element, x, y, z)

    def set_cartesian(self, vector_space):
        '''
        Set the cartesian coordinates of the atom, based on a vector space -
        generally that of a unitcell. Requires column vectors.
        '''
        self.cartesian = vector_space @ self.coordinates.T

我最好使用一个方法来处理所有属性,以保持 class 整洁。我知道我可以只使用“class.attribute”,但据我所知,如果你想重命名某些东西,这可能会导致代码长期中断。

有几种方法可以解决这个问题。需要记住的几件事:

  • Python 没有大量输入——事实上,它几乎没有输入
  • 在编写 python 代码时从 C++ 的角度思考通常很有用

现在,在我看来,您似乎想要一个方法来包含 Atom 的大部分(如果不是全部)属性。如果我要在 C++ 中解决这个问题,我很可能会创建一个 struct 数据类型来使用和使用类似 Atom.GetAttributtes() 到该结构的 return 变量的东西类型。

但是,这是 Python,所以我们可以利用第 1 点:Python 的输入不多。

因此,您可以简单地将 Atom.GetAttrbutes() return 包含所有属性的列表、元组或数组(您甚至可以将包含笛卡尔坐标的数组嵌套在列表中其他属性)

但是,当您说让多个方法获取不同的属性数据“不是 pythonic”时,我不确定您的意思。我会将您的注意力转移到第 2 点:在编写 python 代码时从 C++ 的角度思考通常很有用。

在 C++ 中,拥有多个方法(称为 成员函数 )绝对是处理 return 属性(称为 成员变量 ), 所以这也是在 python 中做事的完美方式。这是因为拥有几个不同的函数 return 不同的属性将使您的程序 运行 更快 。为什么?因为如果您采用上述方法(return将您的属性作为列表、元组或数组)并使用 方式来访问您的属性,您将 运行 遇到这样的情况,比方说,您只想要一个原子的元素,但现在您必须获取所有数据(速度较慢,因为 python 必须找到所有数据并将它们放入列表中)和他们从数据中取出元素(速度较慢,原因很明显。)现在,这并不意味着你不应该有一种方法来一次 return 所有属性(在某些情况下这是有用的也是),但是您也应该有方法来单独访问您的属性。这只是很好的编程,不特定于 C++ 或任何其他语言。