【问题标题】:Internal class objects not resetting after instantiating a custom class in Python 3.6在 Python 3.6 中实例化自定义类后内部类对象未重置
【发布时间】:2018-04-26 17:59:25
【问题描述】:

我正在使用Python 3.6.4 并构建了一个自定义类,我正在其中进行计算并更改其中一个内部类变量。我注意到当我运行算法时它总是正确运行(例如实例化类等)并且总是第二次失败。即使它是同一行代码连续重复两次。我已经能够以更简单的形式复制错误。

为什么第一个对象中正在更改的lr_space 会传播到第二个实例化对象?

class testing(object):
    def __init__(self, 
                n_iter=5,
                n_space=10,
                model_type="logistic",
                lr_space={
                    "C":(1e-6, 1.0),
                    "penalty":["l1", "l2"],
                },
                lr_kws=dict(max_iter=10000, solver="liblinear"),
                ):
        self.n_iter = n_iter
        self.n_space = n_space
        # Logistic Regression
        self.lr_space = lr_space
        self.lr_kws = lr_kws
        print("", self, self.lr_space,"", sep="\n\t")
        self.model_type = model_type.lower()
        self.models = self._test_function()

    def _test_function(self):
        """
        Internal: Label models
        Need to extend this for using different hyperparameters
        """
        models = list()
        self.param_index = OrderedDict()

        # Indexing for hyperparameters and models
        a = np.ones(self.n_iter*2)
        b = np.arange(a.size)
        if self.model_type == "logistic":
            self.lr_space["C"] = np.linspace(*self.lr_space["C"], self.n_space)


        return models
print("=====Instantiating and running `instance_1`=====")
instance_1 = testing()
print("=====Instantiating and running `instance_2`=====")
instance_2 = testing()

输出:

=====Instantiating and running `instance_1`=====

    <__main__.testing object at 0x136154400>
    {'C': (1e-06, 1.0), 'penalty': ['l1', 'l2']}

=====Instantiating and running `instance_2`=====

    <__main__.testing object at 0x127649390>
    {'C': array([  1.00000000e-06,   1.11112000e-01,   2.22223000e-01,
         3.33334000e-01,   4.44445000e-01,   5.55556000e-01,
         6.66667000e-01,   7.77778000e-01,   8.88889000e-01,
         1.00000000e+00]), 'penalty': ['l1', 'l2']}

错误:
-------------------------------------------------- ------------------------- TypeError Traceback(最近一次调用最后一次) 在 () 38 instance_1 = 测试() 39 print("=====实例化和运行instance_2=====") ---> 40 instance_2 = testing()

<ipython-input-342-24f241984973> in __init__(self, n_iter, n_space, model_type, lr_space, lr_kws)
     17         print("", self, self.lr_space,"", sep="\n\t")
     18         self.model_type = model_type.lower()
---> 19         self.models = self._test_function()
     20 
     21     def _test_function(self):

<ipython-input-342-24f241984973> in _test_function(self)
     31         b = np.arange(a.size)
     32         if self.model_type == "logistic":
---> 33             self.lr_space["C"] = np.linspace(*self.lr_space["C"], self.n_space)
     34 
     35 

TypeError: linspace() takes from 2 to 6 positional arguments but 11 were given

【问题讨论】:

  • 尝试在 init 函数中指定 lr_space 的默认值。 IE。 lr_space=None 在定义中,然后如果 lr_space 是 None: lr_space = lr_space={"C":(1e-6, 1.0), "penalty":["l1", "l2"]}

标签: python class instance instantiation self


【解决方案1】:

解决方案:

如果您在 init 函数中指定 lr_space 的默认值,它会起作用:

 from collections import OrderedDict
 import numpy as np

 class testing(object):
     def __init__(self, 
                 n_iter=5,
                 n_space=10,
                 model_type="logistic",
                 lr_space=None,
                 lr_kws=dict(max_iter=10000, solver="liblinear"),
                 ):
         if lr_space is None:
           lr_space = {
                     "C":(1e-6, 1.0),
                     "penalty":["l1", "l2"],
           }
         self.n_iter = n_iter
         self.n_space = n_space
         # Logistic Regression
         self.lr_space = lr_space
         self.lr_kws = lr_kws
         print("", self, self.lr_space,"", sep="\n\t")
         self.model_type = model_type.lower()
         self.models = self._test_function()

     def _test_function(self):
         """
         Internal: Label models
         Need to extend this for using different hyperparameters
         """
         models = list()
         self.param_index = OrderedDict()

         # Indexing for hyperparameters and models
         a = np.ones(self.n_iter*2)
         b = np.arange(a.size)
         if self.model_type == "logistic":
             self.lr_space["C"] = np.linspace(*self.lr_space["C"], self.n_space)


         return models
 print("=====Instantiating and running `instance_1`=====")
 instance_1 = testing()
 print("=====Instantiating and running `instance_2`=====")
 instance_2 = testing()

为什么:

当您为def __init__(...) 中的参数分配默认值时,它们会在新实例存在之前被分配。当使用简单的非可变值(例如5"logistic")时,这无关紧要,但如果您使用字典,则在实例之外创建一个对象,然后将其分配给__init__ 调用中的引用.

这是您应该避免的危险反模式。你可以在这里阅读更多信息:Using a mutable default value as an argument

当您创建新实例时,会再次分配引用,但它仍然引用同一个对象。您上面的代码相当于:

default_dict = {
    "C":(1e-6, 1.0),
    "penalty":["l1", "l2"],
}

class testing(object):
     def __init__(self, 
            n_iter=5,
            n_space=10,
            model_type="logistic",
            lr_space=default_dict,
            lr_kws=dict(max_iter=10000, solver="liblinear"),
            ):

【讨论】:

  • 这也有效,它首先帮助我解决了实际问题。谢谢!
  • 很高兴@O.rka 成功了!您可能希望对 lr_kws=dict(...) 部分执行相同的操作。这可能会导致类似的难以找到的错误。
  • 谢谢@jbch!我将您的链接添加到我的答案中
【解决方案2】:

我最终做的是使用deepcopy 内置的copy

import copy
class testing(object):
    def __init__(self, 
                n_iter=5,
                n_space=10,
                model_type="logistic",
                lr_space={
                    "C":(1e-6, 1.0),
                    "penalty":["l1", "l2"],
                },
                lr_kws=dict(max_iter=10000, solver="liblinear"),
                ):
        self.n_iter = n_iter
        self.n_space = n_space
        # Logistic Regression
        self.lr_space = copy.deepcopy(lr_space)
        self.lr_kws = lr_kws
        print("", self, self.lr_space,"", sep="\n\t")
        self.model_type = model_type.lower()
        self.models = self._test_function()

    def _test_function(self):
        """
        Internal: Label models
        Need to extend this for using different hyperparameters
        """
        models = list()
        self.param_index = OrderedDict()

        # Indexing for hyperparameters and models
        a = np.ones(self.n_iter*2)
        b = np.arange(a.size)
        if self.model_type == "logistic":
            self.lr_space["C"] = np.linspace(*self.lr_space["C"], self.n_space)


        return models

【讨论】:

    猜你喜欢
    • 2013-07-19
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 2016-04-21
    • 2020-06-06
    • 2011-05-03
    • 1970-01-01
    相关资源
    最近更新 更多