11

我对 Python 很陌生,我需要声明自己的数据结构,不过我对如何做到这一点有点困惑。我目前有:

class Particle:

    def __init__(self, mass, position, velocity, force):

        self.mass = mass
        self.position, self.velocity, self.force = position, velocity, force

    def __getitem__(self, mass):
        return self.mass

    def __getitem__(self, position):
        return self.position

    def __getitem__(self, velocity):
        return self.velocity

    def __getitem__(self, force):
        return self.force

但是,当我尝试使用以下方法定义类的实例时,这不起作用:

 p1 = Particle(mass, position, velocity, force)

每个值都以 (0.0, 0.0) 结尾(这是速度和力的值)。

有人可以解释我哪里出错了,我需要从数据结构中提取数据,仅此而已。(编辑:实际上,对不起,我稍后将不得不更改它们)

谢谢

4

6 回答 6

25

首先,您应该了解这__getitem__是语法糖。拥有它很好,但如果你不需要它,就不要使用它。__getitem__并且__setitem__基本上是如果您希望能够使用括号符号访问对象中的项目,例如:

p= Particle(foo)
bar = p[0]

如果您不需要这个,请不要担心。

现在,到其他一切。看起来你已经有了你希望你的对象在你的__init__定义中携带的主要特征,这很好。现在您需要使用以下方法将这些值实际绑定到您的对象上self

class Particle:
    def __init__(self, mass, position, velocity, force):
        self.mass = mass
        self.position = position
        self.velocity = velocity
        self.force = force

就是这样。您现在可以使用点表示法访问这些值,如下所示:

mass,pos,vel,f = 0,0,0,0 # just for readability
p = Particle(mass,pos,vel,f)
print p.mass, p.position, p.velocity, p.force

我们从中得到的好处之一是,如果我们问 python 是什么p,它会告诉你它是该Particle类型的一个实例,如下所示:

in [1]: p
out[1]: <__main__.Particle instance at 0x03E1fE68>

理论上,当您使用这样的对象时,您希望在用户和数据之间有一个“抽象层”,这样他们就不会直接访问或操作数据。为此,您创建函数(就像您尝试使用 所做的那样__getitem__)以通过类方法调解用户和数据之间的交互。这很好,但通常不是必需的。

在您更简单的情况下,要更新这些属性的值,您可以直接按照我们访问它们的方式进行操作,使用点表示法:

in [2]: p.mass
out[2]: 0

in [3]: p.mass = 2 
in [4]: p.mass
out[4]: 2

您可能已经知道这一点,但是__init__函数甚至class定义(您通常/应该定义类的大部分属性和方法的地方)都没有什么神奇之处。某些类型的对象非常允许您随时随地添加属性。这可能很方便,但通常非常hacky并且不是好的做法。我不是建议你这样做,只是告诉你这是可能的。

in [5]: p.newattr ='foobar!'
in [6]: p.newattr
out[6]: 'foobar!'

很奇怪吧?如果这让你的皮肤爬行......好吧,也许它应该。但这是可能的,我是谁说你能做什么和不能做什么。所以这是对课程运作方式的一种体验。

于 2013-03-07T21:15:25.917 回答
8
class Particle:
    def __init__(self, mass, position, velocity, force):
        self.mass = mass
        self.position = position
        self.velocity = velocity
        self.force = force

particle = Particle(1, 2, 3, 4)
print(particle.mass)  # 1

如果你想假装你的类有属性,你可以使用@property装饰器:

class Particle:
    def __init__(self, mass, position, velocity, force):
        self.mass = mass
        self.position = position
        self.velocity = velocity
        self.force = force

    @property
    def acceleration(self):
        return self.force / self.mass

particle = Particle(2, 3, 3, 8)
print(particle.acceleration)  # 4.0
于 2013-03-07T21:11:20.813 回答
4

似乎collections.namedtuple是你所追求的:

from collections import namedtuple

Particle = namedtuple('Particle', 'mass position velocity force')
p = Particle(1, 2, 3, 4)
print p.velocity
于 2013-03-07T21:14:58.870 回答
1

你可以在使用它之前把这个类定义放在前面。如果要声明它,请查看此站点:http ://www.diveintopython.net/getting_to_know_python/declaring_functions.html

顺便说一句,您的问题与这篇文章类似:Is it possible to forward-declare a function in Python? 还有这篇文章:在python中声明它们的主体之前是否可以使用函数?

于 2013-03-07T21:11:06.977 回答
0

如果您需要存储一些属性值(类似于 C 语言struct),您可以这样做:

class myContainer(object):
    pass  # Do nothing

myContainerObj = myContainer()
myContainerObj.storedAttrib = 5
print myContainerObj.storedAttrib
于 2013-03-07T21:19:54.007 回答
0

在 Python 3.7+ 中有数据类库。这个库将允许您创建自己的类来使用装饰器快速保存数据,@dataclass.

装饰器@dataclass允许您快速定义和添加功能到您打算主要用于保存数据的类。

您的问题的数据类可能如下实现。我已经包含了类型提示和默认值,您可能会觉得它们很有帮助。

from dataclasses import dataclass

@dataclass
class Particle:
   mass: float
   position: float
   velocity: float = 0.0
   force: float = 0.0

这是一篇有用的文章,它解释了如何在 Python 3.7+ 中使用数据类和其他一些特性。

于 2021-06-14T15:09:18.267 回答