在 Python 3.6 中实例化自定义 class 后,内部 class 对象未重置
Internal class objects not resetting after instantiating a custom class in Python 3.6
我正在使用 Python 3.6.4
并构建了一个自定义 class,我正在其中进行计算并更改其中一个内部 class 变量。我注意到当我 运行 算法(例如实例化 class 等)时它总是正确运行并且第二次总是失败。即使是同一行代码连续重复两次。我已经能够以更简单的形式复制错误。
为什么第一个对象中正在更改的 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 = 测试()
<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,它会起作用:
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"),
):
我最后做的是使用 copy
内置的 deepcopy
:
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
我正在使用 Python 3.6.4
并构建了一个自定义 class,我正在其中进行计算并更改其中一个内部 class 变量。我注意到当我 运行 算法(例如实例化 class 等)时它总是正确运行并且第二次总是失败。即使是同一行代码连续重复两次。我已经能够以更简单的形式复制错误。
为什么第一个对象中正在更改的 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 = 测试()
<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,它会起作用:
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"),
):
我最后做的是使用 copy
内置的 deepcopy
:
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