web-dev-qa-db-ja.com

カスタムオブジェクトの属性を名前で初期化、設定、取得するPythonの方法は何ですか?

私は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)(速度と力の値)になります。

誰かが私がどこで間違っているのか説明できますか?データ構造から必要なのは、データをそこから引き出すことができることだけです。 (編集:実際、申し訳ありませんが、後で少し変更する必要があります)

ありがとう

10
djcmm476

まず、__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

これから得られる素晴らしい点の1つは、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!'

変だよね?これがあなたの肌を這わせるなら...まあ、多分そうすべきです。しかし、それは可能であり、あなたができることとできないことを私が言うのは誰ですか。これがクラスの仕組みの味です。

20
David Marx
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
8
Waleed Khan

のように思える collections.namedtupleはあなたが求めているものです:

from collections import namedtuple

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

使用する前に、このクラス定義を先に置くことができます。宣言したい場合は、次のサイトを確認してください: http://www.diveintopython.net/getting_to_know_python/declaring_functions.html

ちなみに、あなたの質問はこの投稿に似ています: Pythonで関数を前方宣言することは可能ですか? そしてこの投稿も: 本体を宣言する前に関数を使用することは可能ですか?) Pythonで?

1
tqjustc

justいくつかの属性値を格納する必要がある場合(C言語structと同様)、次のことを実行できます。

class myContainer(object):
    pass  # Do nothing

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