Python类实例丢失疑问:create_object创建的实例为何无法用object2访问?
我正在准备Python考试,练习类与类方法时遇到了一个问题:我创建了一个类实例,它应该存在于类的相关集合中,但却无法通过object2变量获取它。以下是我的代码:
class Watch: instances = [] def __init__(self, model): self.model = model self.eng = "" self.__class__.instances.append(self.model) # 注意:这里存的是型号字符串,不是实例本身 @classmethod def create_new_watch(cls, model, eng): if eng.isalnum() and len(eng) < 40: watch = cls(model) watch.eng = eng else: raise ValueError("Invalid engraving") if len(watch.eng) > 0: print("Your new watch model {} was created".format(watch.model)) print("Your new watch will have the following engraving {}".format(watch.eng)) else: print("Your new watch model {} was created".format(watch.model)) return watch object1 = Watch.create_new_watch("model S", "Newengraving") def create_object(object2, model, eng): try: object2 = Watch.create_new_watch(model, eng) print(object2) print(isinstance(object2, Watch)) except ValueError as e: print(e) else: print("the object was successfully created") create_object("Watch4", "modello T", "Anotherengraving") # 这部分正常,object1是Watch的实例 print(isinstance(object1, Watch)) # 这里报错说object2未定义 print(isinstance(object2, Watch)) # 但类里应该有两个实例,为什么会报错? print(Watch.__dict__)
我的疑问是:object1是有效的Watch类实例,isinstance(object1, Watch)返回True,但调用isinstance(object2, Watch)时却报错,尽管类中已存在两个实例。请问通过create_object函数创建的第二个实例是以什么名称存在的?
1. 为什么object2会报错?
核心问题是变量作用域:你在create_object函数里的object2是局部变量,它只存在于函数执行的过程中。函数结束后,这个局部变量就会被Python的垃圾回收机制处理,全局作用域里根本没有名为object2的变量,所以执行print(isinstance(object2, Watch))时会抛出NameError,提示变量未定义。
另外,你调用create_object("Watch4", "modello T", "Anotherengraving")时传的第一个参数"Watch4"完全没用——函数里直接把object2重新赋值为新创建的实例,原来的参数值被覆盖了,这个参数纯属多余,反而容易误导你以为它和全局的object2有关联。
2. 第二个实例的存在形式
你通过create_object创建的第二个实例,在全局作用域没有绑定任何变量名称。它确实被创建出来了,也被函数里的局部变量object2引用过,但函数执行结束后,这个局部引用消失;再加上你当前的Watch.instances存的是self.model(型号字符串)而非实例本身,所以没有其他地方持有这个实例的引用,Python会自动回收它。
顺便提个小问题:你的Watch.instances列表里添加的是self.model(型号字符串),而不是self(实例对象)。所以你看到Watch.__dict__里的instances有两个元素,那是两个型号字符串,不是实例本身。如果要让instances保存实例,需要把__init__里的代码改成:
self.__class__.instances.append(self)
3. 如何在全局访问这个实例?
如果想在全局作用域获取这个实例,需要让create_object函数返回它,然后在调用时赋值给全局变量:
# 修改函数,去掉多余的object2参数,返回创建的实例 def create_object(model, eng): try: watch_instance = Watch.create_new_watch(model, eng) print(watch_instance) print(isinstance(watch_instance, Watch)) except ValueError as e: print(e) return None # 出错时返回None else: print("the object was successfully created") return watch_instance # 调用函数并赋值给全局的object2 object2 = create_object("modello T", "Anotherengraving") # 现在就能正常检查了 print(isinstance(object2, Watch))
这样,object2就会在全局作用域绑定到新创建的实例,你就能正常访问它了。
内容的提问来源于stack exchange,提问作者Tommy D

