【问题标题】:Why are my Class member variables going missing in Python?为什么我的类成员变量在 Python 中丢失了?
【发布时间】:2017-09-09 15:34:37
【问题描述】:

我上课了。我认为我在初始化程序/构造函数中创建了一个名为“myTup”的成员变量。我试图通过在初始化程序的最后进行以下调用来确保我确实创建了 myTup:

assert(hasattr(self, 'myTup'))

但是,后来解释器说我的实例/对象没有名为“myTup”的成员变量。

myTup 去哪儿了?回到我身边……请Q_Q

由于所有的小调试语句,以下脚本很长。不用调试,其实很短很简单。

代码:

import inspect
def lineno():
    # Returns the current line number in our program.
    return inspect.currentframe().f_back.f_lineno

class DemoClass:

    def __init__(self, initial_data):

        went_in = False # did not enter the if-elif-else block

        if isinstance(initial_data, str):
            print('line number:', lineno())
            t = tuple(initial_data)
            self = DemoClass(t)
            went_in = True        
        elif isinstance(initial_data, DemoClass):
            print('line number:', lineno())
            self = initial_data
            went_in = True
        elif isinstance(initial_data, tuple):
            print('line number:', lineno())
            self.myTup = initial_data
            went_in = True
        else:
            print('line number:', lineno())
            went_in = True
            assert(False)

        assert(hasattr(self, 'myTup'))
        print('line number:', lineno())
        print('went_in:', went_in)
        print('myTup:', self.myTup)

    def __str__(self):
        return "DemoClass" + str(self.myTup)

obj = DemoClass("s")
print(obj)

输出:

line number: 13
line number: 22
line number: 31
went_in: True
myTup: ('s',)
line number: 31
went_in: True
myTup: ('s',)
Traceback (most recent call last):

  [... truncated / abridged ...]

  File "E:/awesome_folder_name/missing_member_var.py", line 36, in __str__
    return "DemoClass" + str(self.myTup)

AttributeError: 'DemoClass' object has no attribute 'myTup'

【问题讨论】:

  • 为什么要重新定义self
  • self = DemoClass(t) 行是您的问题。您的代码想要重载__init__() 以处理initial_data 的不同类型(这很好),但不要尝试从自身递归调用__init__,并且永远不要尝试覆盖对象或其方法内的任何地方的self .
  • 整个line_no,went_in 检测代码很古怪,它只是让事情变得混乱。您不需要 if-else 阶梯来处理 initial_data 的多种类型。
  • 您希望使用 initial_data 的三种不同可能性调用 DemoClass.__init__():字符串、元组或 DemoClass 的现有实例。最后一个很奇怪:你是想复制还是克隆一个对象? (使用复制())。做你所做的没有意义:将给定的 DemoClass 实例包装在 DemoClass 的新实例中。你不能访问它的initial_data,除非写obj. initial_data.initial_data
  • 您可能会发现CodeReview.SE 很有帮助

标签: python python-3.x class methods member-variables


【解决方案1】:

您无法替换在__init__ 中创建的实例。以下内容仅替换 __init__ 方法中的 self 引用,不是 self 绑定到的先前实例

if isinstance(initial_data, str):
    # ...
    t = tuple(initial_data)
    self = DemoClass(t)

__init__ 返回时,obj = DemoClass("s") 行仍然绑定第一个实例,而不是您使用递归调用创建的实例。第一个实例没有myTup 属性。

您必须调用 self.__init__(t) 而不是对同一实例进行操作:

if isinstance(initial_data, str):
    # ...
    t = tuple(initial_data)
    self.__init__(t)

然后再次调用__init__,绑定相同的实例,因此将在正确的对象上设置myTup

请注意,我会避免在这里使用递归。没必要,在不同的分支中设置一个元组,最后赋值myTup即可:

def __init__(self, initial_data):
    if isinstance(initial_data, str):
        initial_data = tuple(initial_data)
    elif isinstance(initial_data, DemoClass):
        initial_data = initial_data.myTup
    elif not isinstance(initial_data, tuple):
        raise ValueError('Invalid data')

    self.myTup = initial_data

如果您必须在尝试使用DemoClass() 创建新实例时控制返回的实例,那么您只能使用__new__ method 执行此操作;它首先负责生成实例(之后默认实现将在该新实例上调用__init__)。

【讨论】:

    猜你喜欢
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    相关资源
    最近更新 更多