在Python 3.6中实例化自定义类后,内部类对象未重置

时间:2018-04-26 17:59:26

标签: python class instance instantiation self

我正在使用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(最近一次调用最后一次)      in()          38 instance_1 = testing()          39打印(“=====实例化并运行instance_2 =====”)     ---&GT; 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

2 个答案:

答案 0 :(得分:0)

解决方案:

如果在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")时这并不重要,但是如果使用dict,则在实例外部创建对象,然后将其分配给引用在__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"),
            ):

答案 1 :(得分:0)

我最终做的是使用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