什么是Pythonic按名称初始化,设置和获取自定义对象属性的方法?

时间:2013-03-07 21:05:48

标签: python object properties attributes

我对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 个答案:

答案 0 :(得分:20)

首先,你应该明白__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!'

奇怪吧?如果这让你的皮肤爬行......好吧,也许它应该。但这是可能的,我应该说出你能做什么,不能做什么。这就是了解课程的运作方式。

答案 1 :(得分: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

答案 2 :(得分:4)

似乎collections.namedtuple就像你所追求的那样:

from collections import namedtuple

Particle = namedtuple('Particle', 'mass position velocity force')
p = Particle(1, 2, 3, 4)
print p.velocity

答案 3 :(得分:1)

您可以在使用之前将此类定义放在前面。如果您要申报,请查看此网站:http://www.diveintopython.net/getting_to_know_python/declaring_functions.html

顺便提一下,您的问题与此帖相似:Is it possible to forward-declare a function in Python?以及此帖:Is it possible to use functions before declaring their body in python?

答案 4 :(得分:0)

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

class myContainer(object):
    pass  # Do nothing

myContainerObj = myContainer()
myContainerObj.storedAttrib = 5
print myContainerObj.storedAttrib

答案 5 :(得分: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

Here is a useful article 解释了如何在 Python 3.7+ 和其他一些特性中使用数据类。