web-dev-qa-db-ja.com

Pythonオブジェクト自体を削除する

なぜこれが機能しないのですか?クラスのインスタンスを自分自身で削除しようとしています。

>>> class A():
    def kill(self):
        del self


>>> a = A()
>>> a.kill()
>>> a
<__main__.A instance at 0x01F23170>
60
Null

「自己」はオブジェクトへの参照にすぎません。 「del self」は、実際のオブジェクトではなく、kill関数のローカル名前空間から「self」参照を削除しています。

これを自分で確認するには、これら2つの関数が実行されたときに何が起こるかを見てください。

>>> class A():
...     def kill_a(self):
...         print self
...         del self
...     def kill_b(self):
...         del self
...         print self
... 
>>> a = A()
>>> b = A()
>>> a.kill_a()
<__main__.A instance at 0xb771250c>
>>> b.kill_b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in kill_b
UnboundLocalError: local variable 'self' referenced before assignment
68
Jeremy Ruten

最初にインスタンスを削除するためにdelを使用する必要はありません。オブジェクトへの最後の参照がなくなると、オブジェクトはガベージコレクションされます。たぶん、あなたは完全な問題についてもっと教えてください。

42
Ned Batchelder

この特定のコンテキストでは、例はあまり意味がありません。

存在がアイテムを拾うと、アイテムは個々の存在を保持します。拾われているので消えません。それはまだ存在しますが、(a)存在と同じ場所にあり、(b)もう拾う資格がありません。状態が変更されましたが、まだ存在しています。

存在とアイテムの間には双方向の関連性があります。存在はコレクションにアイテムを持っています。アイテムは存在に関連付けられています。

アイテムが存在によって拾われるとき、2つのことが起こらなければなりません。

  • Being howは、アイテムのsetにアイテムを追加します。たとえば、bag属性はsetになります。 [listは選択肢として不適切です-バッグの中の順序は重要ですか?]

  • アイテムの場所は、以前の場所から存在の場所に変わります。アイテムには、おそらく2つのクラスがあります-独立した場所の感覚を持つアイテム(自分で動き回るので)と、座っている場所または存在に場所を委任する必要があるアイテムです。

どんな状況でもPythonオブジェクトを削除する必要はありません。アイテムが「破壊された」場合、それはBeing's bagにありません。それは場所にありません。

player.bag.remove(cat)

猫を袋から取り出すのに必要なのはそれだけです。猫は他の場所では使用されないため、「使用済み」メモリとして存在し、プログラム内の何もアクセスできないため存在しません。量子イベントが発生し、メモリ参照がガベージコレクションされると、メモリから静かに消えます。

一方、

here.add( cat )
player.bag.remove(cat)

現在の場所に猫を置きます。猫は存在し続け、ゴミと一緒に出されません。

13
S.Lott

やっと手に入れたと思います!
注:通常のコードではこれを使用しないでくださいですが、possibleです。これは単なる好奇心を意味するものであり、この問題に対する実際のソリューションに関する他の回答を参照してください。


# NOTE: This is Python 3 code, it should work with python 2, but I haven't tested it.
import weakref

class InsaneClass(object):
    _alive = []
    def __new__(cls):
        self = super().__new__(cls)
        InsaneClass._alive.append(self)

        return weakref.proxy(self)

    def commit_suicide(self):
        self._alive.remove(self)

instance = InsaneClass()
instance.commit_suicide()
print(instance)

# Raises Error: ReferenceError: weakly-referenced object no longer exists

オブジェクトが__new__メソッドで作成されると、インスタンスは弱参照プロキシによって置き換えられ、強参照のみが_aliveクラス属性に保持されます。

弱参照とは何ですか?

弱参照は、ガベージコレクターがオブジェクトを収集するときに参照としてカウントされない参照です。この例を考えてみましょう:

>>> class Test(): pass

>>> a = Test()
>>> b = Test()

>>> c = a
>>> d = weakref.proxy(b)
>>> d
<weakproxy at 0x10671ae58 to Test at 0x10670f4e0> 
# The weak reference points to the Test() object

>>> del a
>>> c
<__main__.Test object at 0x10670f390> # c still exists

>>> del b
>>> d
<weakproxy at 0x10671ab38 to NoneType at 0x1002050d0> 
# d is now only a weak-reference to None. The Test() instance was garbage-collected

したがって、インスタンスへの唯一の強い参照は、_aliveクラス属性に格納されます。そして、commit_suicide()メソッドが参照を削除すると、インスタンスはガベージコレクションされます。

13
les

現実的には、あなたがやろうとしていることをするためにオブジェクトを削除する必要はないはずです。代わりに、オブジェクトの状態を変更できます。コーディングを行わずにこれがどのように機能するかの例は、プレイヤーがモンスターと戦い、モンスターを殺すことです。このモンスターの状態は戦っている。モンスターは戦闘に必要なすべての方法にアクセスします。モンスターの体力が0に低下したためにモンスターが死亡すると、モンスターの状態は死に変わり、キャラクターは自動的に攻撃を停止します。この方法論は、フラグまたはキーワードを使用することと非常に似ています。

また、どうやらpythonクラスを削除する必要はありません。クラスが使用されなくなったときに自動的にガベージコレクションされるためです。

4
Zachary Kraus

私は同じことを試みています。私のRPGバトルシステムでは、Death(self)関数がFighterクラスの自身のオブジェクトを殺さなければなりません。しかし、それは不可能だと思われました。たぶん、戦闘ですべての参加者を集めた私のクラスのゲームは、「架空の」マップからユニットを削除するべきでしょうか?

   def Death(self):
    if self.stats["HP"] <= 0:
        print("%s wounds were too much... Dead!"%(self.player["Name"]))
        del self
    else:
        return True

def Damage(self, enemy):
    todamage = self.stats["ATK"] + randint(1,6)
    todamage -= enemy.stats["DEF"]
    if todamage >=0:
        enemy.stats["HP"] -= todamage
        print("%s took %d damage from your attack!"%(enemy.player["Name"], todamage))
        enemy.Death()
        return True
    else:
        print("Ineffective...")
        return True
def Attack(self, enemy):
    tohit = self.stats["DEX"] + randint(1,6)
    if tohit > enemy.stats["EVA"]:
        print("You landed a successful attack on %s "%(enemy.player["Name"]))
        self.Damage(enemy)
        return True
    else:
        print("Miss!")
        return True
def Action(self, enemylist):
    for i in range(0, len(enemylist)):
        print("No.%d, %r"%(i, enemylist[i]))
    print("It`s your turn, %s. Take action!"%(self.player["Name"]))
    choice = input("\n(A)ttack\n(D)efend\n(S)kill\n(I)tem\n(H)elp\n>")
    if choice == 'a'or choice == 'A':
        who = int(input("Who? "))
        self.Attack(enemylist[who])
        return True
    else:
        return self.Action()
3
Ilian Zapryanov

クラスでこれがどのように可能かはわかりませんが、関数は自分自身を削除できます。

def kill_self(exit_msg = 'killed'):
    global kill_self
    del kill_self
    return exit_msg

そして出力を見てください:

 >>> kill_self
<function kill_self at 0x02A2C780>
>>> kill_self()
'killed'
>>> kill_self
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    kill_self
NameError: name 'kill_self' is not defined

クラスの名前を知らずにクラスの個々のインスタンスを削除することは不可能だと思います。

注:関数に別の名前を割り当てた場合、別の名前は引き続き古い名前を参照しますが、実行しようとするとエラーが発生します。

>>> x = kill_self
>>> kill_self()
>>> kill_self
NameError: name 'kill_self' is not defined
>>> x
<function kill_self at 0x...>
>>> x()
NameError: global name 'kill_self' is not defined
3

オブジェクトへの単一の参照を使用している場合は、次のように、オブジェクトへの外部参照をリセットすることにより、オブジェクトが自身を殺すことができます。

class Zero:
    pOne = None

class One:

    pTwo = None   

    def process(self):
        self.pTwo = Two()
        self.pTwo.dothing()
        self.pTwo.kill()

        # now this fails:
        self.pTwo.dothing()


class Two:

    def dothing(self):
        print "two says: doing something"

    def kill(self):
        Zero.pOne.pTwo = None


def main():
    Zero.pOne = One() # just a global
    Zero.pOne.process()


if __name__=="__main__":
    main()

たとえば、次のように、オブジェクトの状態ではなく、オブジェクトの外部からオブジェクトの存在を確認することで、ロジック制御を行うことができます。

if object_exists:
   use_existing_obj()
else: 
   obj = Obj()
1
Basel Shishani

実際、Pythonは参照カウントを通じてガベージコレクションを行います。オブジェクトへの最後の参照が範囲外になるとすぐに削除されます。例では:

a = A()
a.kill()

変数 'a'が暗黙的にNoneに設定する方法はないと思います。

1
Cybis

なぜそんなことをしたいのか興味があります。ガベージコレクションに任せてください。 Pythonでは、ガベージコレクションはかなり確定的です。そのため、他の言語の場合のように、オブジェクトをメモリ内に置くだけで心配する必要はありません(refcountingにデメリットがないと言わないでください)。

考慮すべきことの1つは、後で削除できるオブジェクトまたはリソースのラッパーです。

class foo(object):
    def __init__(self):
        self.some_big_object = some_resource

    def killBigObject(self):
        del some_big_object

Nullの補遺 への応答:

残念ながら、私はあなたがやりたいことをやりたい方法をする方法があるとは思わない。検討したい方法の1つを次に示します。

>>> class manager(object):
...     def __init__(self):
...             self.lookup = {}
...     def addItem(self, name, item):
...             self.lookup[name] = item
...             item.setLookup(self.lookup)
>>> class Item(object):
...     def __init__(self, name):
...             self.name = name
...     def setLookup(self, lookup):
...             self.lookup = lookup
...     def deleteSelf(self):
...             del self.lookup[self.name]
>>> man = manager()
>>> item = Item("foo")
>>> man.addItem("foo", item)
>>> man.lookup
 {'foo': <__main__.Item object at 0x81b50>}
>>> item.deleteSelf()
>>> man.lookup
 {}

それは少し厄介ですが、それはあなたにアイデアを与える必要があります。基本的に、ゲーム内のアイテムの存在を、メモリ内に割り当てられているかどうかに結び付けることは良い考えだとは思いません。これは、ガベージコレクションされるアイテムの条件が、ゲーム内のアイテムの条件とは異なる可能性が高いためです。このように、あなたはそれについてそれほど心配する必要はありません。

0
Jason Baker
class A:
  def __init__(self, function):
    self.function = function
  def kill(self):
    self.function(self)

def delete(object):                        #We are no longer in A object
  del object

a = A(delete)
print(a)
a.kill()
print(a)

このコードは機能しますか?

0
Anonyme

あなたができることはクラスであなたと一緒に名前を取り、辞書を作ることです:

class A:
  def __init__(self, name):
    self.name=name
  def kill(self)
    del dict[self.name]

dict={}
dict["a"]=A("a")
dict["a"].kill()
0
Theoxis

これは私が過去にしたことです。オブジェクトのリストを作成すると、list.remove()メソッドを使用してオブジェクトを自分自身で削除できます。

bullet_list = []

class Bullet:
    def kill_self(self):
        bullet_list.remove(self)

bullet_list += [Bullet()]
0
Henry