使用我不想要的对象上课

 收藏

我正在学习课程,这件事使我发疯。每当我运行此命令时,即使我从未使用过del droid1,del droid2或del droid3,它也会使用del对象。有人可以帮忙吗?

class Robots:
    '''Represents a robot, with a name.'''

    #A class variable, counting the number of robots
    population = 0

    def __init__(self, name):
        '''Initializes the data'''
        self.name = name
        print("(Initializing {0})".format(self.name))

        #When this person is created, the robot adds to the population
        Robots.population += 1

    def __del__(self):
        '''I am dying'''
        print("{0} is being destoryed!".format(self.name))

        Robot.population -= 1

        if Robot.population == 0:
            print("{0} was the last one.".format(self.name))
        else:
            print("There are still {0:d} robots working".format(Robot.population))


    def sayHi(self):
        '''Greeting by the robot

        yeah, they can do that.'''
        print("Greetings, my masters call me {0}".format(self.name))

    def howMany():
        '''Prints the current population'''
        print("We have {0:d} robots.".format(Robots.population))
    howMany = staticmethod(howMany)

droid1 = Robots("r2-d2")
droid2 = Robots("c-3po")
droid3 = Robots("SAL")

droid1.sayHi()
droid2.sayHi()
droid3.sayHi()
回复
  • et_ea 回复

    我会很乐意使用一个机器人列表(如果不仅是名称列表),而且使用简单的len()作为人口信息(机器人中没有__del__方法)是一个古老的化石,但是当然,您不会从中学习任何OO。那。即使大多数情况下,我也避免使用staticmethod方法,但是当使用类变量并且在方法内部未使用实例时(而不是使用常规函数),也许它们可以放置位置

  • 借个吻 回复

    I agree with tony that everything is fine if you replace Robots by Robot. However my advice is not to define objects with a __del__() method because they can create uncollectable objects if they are part of a reference cycle (read the documentation of gc.garbage about this). There are other techniques if you want to keep track of the number of living robots, for example use a weakref.WeakValueDictionary with the object's id() as key. The number of robots would be the length of this dictionary.
    Notice that the python documentation says explicitely that you don't know when an object is collected, which means that you can't predict when python's garbage collector will call your __del__() method after the objects vanishes from the program's namespace, although in practice, the object seems to be collected immediately.
    Also there is no guarantee that the __del__() method will be called at all, which is another reason not to use this method. In your case, the method is called when the memory is freed at interpreter's exit.

  • ~那么美 回复

    是的,但是由于他的机器人之间没有相互引用,所以在这里不可能发生这种情况。

    我同意这一点,但可能是明年他将要向机器人实例添加一个列表,其中包含Foo实例,这些实例又引用了其他机器人,这是内存泄漏。确保python程序中没有循环引用几乎是不可能的:)。我的规则比较安全,没有del方法就可以生存。

  • 旗才艺 回复

    :( 我上了学……好吧,至少我学到了一些东西。

    但是,我的方法行不通吗?

    在类外声明变量,它会在每次创建或删除对象时存储加减法吗?

  • wfuga 回复

    但是我的建议是不要用del()方法定义对象,因为如果它们是引用周期的一部分,则它们可以创建无法收集的对象

    是的,但是由于他的机器人之间没有相互引用,所以在这里不可能发生这种情况。

    另外,也不保证将完全调用del()方法,这是不使用此方法的另一个原因。

    It's only not guarantued if the object is still alive at the end of the program, in which case it wouldn't matter for this use-case since there's no way to callRobot.howMany() after the program ended.

  • 以後呢? 回复

    Here is an implementation with the WeakValueDictionary. It has the same result as the __del__ method, but, as far as I know, there is no garbage collection issue.

    #!/usr/bin/python3
    # -*-coding: utf8-*-
    
    from functools import partial
    import weakref
    
    def del_robot(name, wref):
        '''A robot is dying'''
        print("{0} is being destroyed!".format(name))
        population = len(Robot._living_instances)
        if population:
            print("There are still {0:d} robots working".format(population))
        else:
            print("{0} was the last one".format(name))
    
    class Robot:
        '''Represents a robot, with a name.'''
    
        #A class variable, counting the number of Robot
        _living_instances = weakref.WeakValueDictionary()
    
        def __init__(self, name):
            '''Initializes the data'''
            self.name = name
            self._wref = weakref.ref(self, partial(del_robot, self.name))
            self._living_instances[id(self)] = self
            print("(Initializing {0})".format(self.name))
    
        def sayHi(self):
            '''Greeting by the robot
    
            yeah, they can do that.'''
            print("Greetings, my masters call me {0}".format(self.name))
    
        @classmethod
        def howMany(cls):
            '''Prints the current population'''
            print("We have {0:d} Robots (some of them may be dead already, but it is unlikely).".format(
                len(cls._living_instances)))
    
        @classmethod
        def reliable_count(cls):
            return len(cls._living_instances.values())
    
    droid1 = Robot("r2-d2")
    droid2 = Robot("c-3po")
    droid3 = Robot("SAL")
    
    droid1.sayHi()
    droid2.sayHi()
    droid3.sayHi()
    
    del droid1
    Robot.howMany()
    
    """My output -->
    (Initializing r2-d2)
    (Initializing c-3po)
    (Initializing SAL)
    Greetings, my masters call me r2-d2
    Greetings, my masters call me c-3po
    Greetings, my masters call me SAL
    r2-d2 is being destroyed!
    There are still 2 robots working
    We have 2 Robots (some of them may be dead already, but it is unlikely).
    c-3po is being destroyed!
    There are still 1 robots working
    SAL is being destroyed!
    SAL was the last one
    """
    

  • sest 回复

    因此,首先,Robot在任何地方都不是定义的变量,因此Robot.population毫无意义。

    其次,您使用人口的方式行不通。每次您制作新的机器人时,填充将重置为0,只有该机器人的填充将为0。

    您将需要重新考虑您的类将如何工作,并且,如果您想跟踪机器人类的实例数量,则可能需要一个全局变量(或者至少需要一个类本身之外的变量),否则该类的实例将添加到模块中的变量中。

  • Harry 回复

    您只有机器人而不是机器人,因为名称错误,否则一切似乎都很好。

    class Robot:
        '''Represents a robot, with a name.'''
    
        #A class variable, counting the number of Robot
        population = 0
    
        def __init__(self, name):
            '''Initializes the data
            '''
            self.name = name
            print("(Initializing {0})".format(self.name))
    
            #When this person is created, the robot adds to the population
            Robot.population += 1
    
        def __del__(self):
            '''I am dying
            '''
            print("{0} is being destoryed!".format(self.name))
    
            Robot.population -= 1
    
            if Robot.population == 0:
                print("{0} was the last one.".format(self.name))
            else:
                print("There are still {0:d} Robot{1} working".format(Robot.population, ('s' if Robot.population > 1 else '')))
    
    
        def say_hi(self):
            '''Greeting by the robot
            yeah, they can do that.
            '''
            print("Greetings, my masters call me {0}".format(self.name))
    
        @staticmethod
        def how_many():
            '''Prints the current population
            '''
            print("We have {0:d} Robot.".format(Robot.population))
    
    droid1 = Robot("r2-d2")
    droid2 = Robot("c-3po")
    droid3 = Robot("SAL")
    
    droid1.say_hi()
    droid2.say_hi()
    droid3.say_hi()
    Robot.how_many()
    
    del droid2
    droids = [droid1, droid3]
    del droid1
    # population does not change as droid1 reference still exist
    Robot.how_many()
    del droids[0]
    Robot.how_many()