用Pythonic方式通过名称初始化、设置和获取自定义对象属性的方法是什么?

12 投票
6 回答
27662 浏览
提问于 2025-04-17 18:19

我刚开始学习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),这代表速度和力的值。

有人能告诉我哪里出错了吗?我只需要这个数据结构能让我提取里面的数据,其他的没什么要求。(补充一下:其实,抱歉,我稍后可能还会对它们做些修改)

谢谢!

6 个回答

4

看起来你想要的是 collections.namedtuple 这个东西:

from collections import namedtuple

Particle = namedtuple('Particle', 'mass position velocity force')
p = Particle(1, 2, 3, 4)
print p.velocity
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
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

如果你想让你的类看起来像是有属性一样,可以使用 @property 装饰器:

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 定义(你通常会在这里定义大部分类的属性和方法)并没有什么神奇之处。某些类型的对象允许你随时随地添加属性。这虽然方便,但通常是比较“黑客”的做法,不是好习惯。我并不是建议你这样做,只是告诉你这是可能的。

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

奇怪吧?如果这让你感到不安……嗯,也许应该这样。但这确实是可能的,我又有什么资格说你能做什么不能做什么呢。所以这就是类是如何工作的一个简单介绍。

撰写回答