Python object deleting itself

后端 未结 14 1873
一向
一向 2020-11-27 04:23

Why won\'t this work? I\'m trying to make an instance of a class delete itself.

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


>>>          


        
相关标签:
14条回答
  • 2020-11-27 04:48

    In this specific context, your example doesn't make a lot of sense.

    When a Being picks up an Item, the item retains an individual existence. It doesn't disappear because it's been picked up. It still exists, but it's (a) in the same location as the Being, and (b) no longer eligible to be picked up. While it's had a state change, it still exists.

    There is a two-way association between Being and Item. The Being has the Item in a collection. The Item is associated with a Being.

    When an Item is picked up by a Being, two things have to happen.

    • The Being how adds the Item in some set of items. Your bag attribute, for example, could be such a set. [A list is a poor choice -- does order matter in the bag?]

    • The Item's location changes from where it used to be to the Being's location. There are probably two classes os Items - those with an independent sense of location (because they move around by themselves) and items that have to delegate location to the Being or Place where they're sitting.

    Under no circumstances does any Python object ever need to get deleted. If an item is "destroyed", then it's not in a Being's bag. It's not in a location.

    player.bag.remove(cat)
    

    Is all that's required to let the cat out of the bag. Since the cat is not used anywhere else, it will both exist as "used" memory and not exist because nothing in your program can access it. It will quietly vanish from memory when some quantum event occurs and memory references are garbage collected.

    On the other hand,

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

    Will put the cat in the current location. The cat continues to exist, and will not be put out with the garbage.

    0 讨论(0)
  • 2020-11-27 04:49

    I think I've finally got it!
    NOTE: You should not use this in normal code, but it is possible. This is only meant as a curiosity, see other answers for real-world solutions to this problem.


    Take a look at this code:

    # 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
    

    When the object is created in the __new__ method, the instance is replaced by a weak reference proxy and the only strong reference is kept in the _alive class attribute.

    What is a weak-reference?

    Weak-reference is a reference which does not count as a reference when the garbage collector collects the object. Consider this example:

    >>> 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
    

    So the only strong reference to the instance is stored in the _alive class attribute. And when the commit_suicide() method removes the reference the instance is garbage-collected.

    0 讨论(0)
  • 2020-11-27 04:52

    'self' is only a reference to the object. 'del self' is deleting the 'self' reference from the local namespace of the kill function, instead of the actual object.

    To see this for yourself, look at what happens when these two functions are executed:

    >>> 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
    
    0 讨论(0)
  • 2020-11-27 04:55

    Indeed, Python does garbage collection through reference counting. As soon as the last reference to an object falls out of scope, it is deleted. In your example:

    a = A()
    a.kill()
    

    I don't believe there's any way for variable 'a' to implicitly set itself to None.

    0 讨论(0)
  • 2020-11-27 04:58

    Realistically you should not need to delete the object to do what you are trying to do. Instead you can change the state of the object. An example of how this works without getting into the coding would be your player fighting a monster and killing the monster. The state of this monster is fighting. The monster will be accessing all methods needed for fighting. When the monster dies because his health drops to 0, the monsters state will change to dead and your character will stop attacking automatically. This methodology is very similar to using flags or even keywords.

    Also apparently in python deleting classes is not required since they will be garbage collected automatically when they are not used anymore.

    0 讨论(0)
  • 2020-11-27 04:58

    A replacement implement:

    class A:
    
        def __init__(self):
            self.a = 123
    
        def kill(self):
            from itertools import chain
            for attr_name in chain(dir(self.__class__), dir(self)):
                if attr_name.startswith('__'):
                    continue
                attr = getattr(self, attr_name)
                if callable(attr):
                    setattr(self, attr_name, lambda *args, **kwargs: print('NoneType'))
                else:
                    setattr(self, attr_name, None)
            a.__str__ = lambda: ''
            a.__repr__ = lambda: ''
    
    a = A()
    print(a.a)
    a.kill()
    
    print(a.a)
    a.kill()
    
    a = A()
    print(a.a)
    

    will outputs:

    123
    None
    NoneType
    123
    
    0 讨论(0)
提交回复
热议问题