Pythonでオブジェクトのリストを作成する


83

複数のデータベースを開いてその内容を比較するPythonスクリプトを作成しようとしています。そのスクリプトを作成する過程で、自分が作成したオブジェクトを内容とするリストを作成する際に問題が発生しました。

この投稿のために、プログラムを必要最低限​​に簡略化しました。まず、新しいクラスを作成し、その新しいインスタンスを作成し、それに属性を割り当ててから、リストに書き込みます。次に、インスタンスに新しい値を割り当て、それをリストに書き込みます...そして何度も何度も...

問題は、それは常に同じオブジェクトなので、実際にはベースオブジェクトを変更しているだけです。リストを読むと、同じオブジェクトが何度も繰り返されます。

では、ループ内のリストにオブジェクトをどのように書き込むのでしょうか。

これが私の簡略化されたコードです

class SimpleClass(object):
    pass

x = SimpleClass
# Then create an empty list
simpleList = []
#Then loop through from 0 to 3 adding an attribute to the instance 'x' of SimpleClass
for count in range(0,4):       
    # each iteration creates a slightly different attribute value, and then prints it to
# prove that step is working
# but the problem is, I'm always updating a reference to 'x' and what I want to add to
# simplelist is a new instance of x that contains the updated attribute

x.attr1= '*Bob* '* count
print "Loop Count: %s Attribute Value %s" % (count, x.attr1)
simpleList.append(x)

print '-'*20
# And here I print out each instance of the object stored in the list 'simpleList'
# and the problem surfaces.  Every element of 'simpleList' contains the same      attribute value

y = SimpleClass
print "Reading the attributes from the objects in the list"
for count in range(0,4):
    y = simpleList[count]
    print y.attr1

では、simpleListの要素を(追加、拡張、コピーなど)どのようにして、すべてのエントリが同じオブジェクトを指すのではなく、オブジェクトの異なるインスタンスを含むようにするのでしょうか。


2
カウンターの代わりにイテレーターを使用することをお勧めします。「simpleListのアイテムの場合:」の方がはるかに見栄えがします。
Mapad 2008

回答:


70

あなたは根本的な誤解を示しています。

SimpleClassのインスタンスを呼び出さなかったため、インスタンスを作成したことはありません。

for count in xrange(4):
    x = SimpleClass()
    x.attr = count
    simplelist.append(x)

または、クラスにパラメーターをとらせる場合は、代わりにリスト内包表記を使用できます。

simplelist = [SimpleClass(count) for count in xrange(4)]

2
Python 3.xでは使用できません-xrange()funcはサポートされなくなりました。
r3t 4019

3
@TitPoplatnik単にxrange()をrange()に置き換えます。
エクスプレス

@ironfroggyは、クラス内からオブジェクトが格納されているインデックスを取得することができます。言うクラスAは、いくつかのリスト内の位置3にある場合、[X、X、X、A、x]は、それがAのドームの方法を実施することにより位置を取得することが可能である
アレクサンダーCSKAを

55

クラスの個別のインスタンスでリストを埋めるには、リストの宣言でforループを使用できます。*乗算は、各コピーを同じインスタンスにリンクします。

instancelist = [ MyClass() for i in range(29)]

次に、リストのインデックスを介してインスタンスにアクセスします。

instancelist[5].attr1 = 'whamma'

3
良く:instancelist = [MyClassの()(29)の範囲内_用]
tutormike

11

SimpleClassオブジェクトを使用して属性に基づいてデータを出力するだけの場合は、SimpleClassオブジェクトを毎回再作成する必要はないはずです。ただし、実際にはクラスのインスタンスを作成しているわけではありません。クラスオブジェクト自体への参照を作成しているだけです。したがって、同じクラス属性への参照を(インスタンス属性ではなく)リストに何度も追加していることになります。

の代わりに:

x = SimpleClass

必要なもの:

x = SimpleClass()

7
x = SimpleClass() されたオブジェクトを毎回再作成。
ニール2013年

5

同じインスタンスの状態を継続的に変更するのではなく、毎回新しいインスタンスを作成します。新しいインスタンスはそれぞれ正しい状態になります。

または、元のオブジェクトではなく、明示的に作成されたオブジェクトのコピー(このページのヒント使用)を各ステップで保存します。


3

私があなたの質問を正しく理解しているなら、あなたはオブジェクトのディープコピーを実行する方法を尋ねます。copy.deepcopyを使用するのはどうですか?

import copy

x = SimpleClass()

for count in range(0,4):
  y = copy.deepcopy(x)
  (...)
  y.attr1= '*Bob* '* count

ディープコピーは、オブジェクト全体の再帰的なコピーです。詳細については、Pythonのドキュメントをご覧くださいhttps//docs.python.org/2/library/copy.html


2
オブジェクト(ディープコピーまたはクローン)の再利用は、n00bでよくある混乱です。時々あなたは尋ねるように見える質問に答えることができない。時々あなたは彼らが尋ねるべきだった質問に答えなければなりません。
S.Lott 2008

3

これは、あなたが達成しようとしていることを単に示していると思います。

# coding: utf-8

class Class():
    count = 0
    names = []

    def __init__(self,name):
        self.number = Class.count
        self.name = name
        Class.count += 1
        Class.names.append(name)

l=[]
l.append(Class("uno"))
l.append(Class("duo"))
print l
print l[0].number, l[0].name
print l[1].number, l[1].name
print Class.count, Class.names

上記のコードを実行すると、次のようになります。-

[<__main__.Class instance at 0x6311b2c>, 
<__main__.Class instance at 0x63117ec>]
0 uno
1 duo
2 ['uno', 'duo']
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.