TypeError:“类名”对象不可调用

时间:2019-04-05 19:20:01

标签: python python-2.7 scipy

我正在研究使用“ x,y”数据集的类。数据通常来自txt文件,其中数据的第一列存储在“ x”中,第二列存储在“ y”中。

我正在向类添加一些“曲线拟合”功能。我在这篇文章的标题中遇到了错误。

这是课程:

class XY(object):
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    import numpy as np
    def __init__(self,f=None):
        self.file(f)
        self.read()
        return
    def file(self,f=None):
        self.filename=self.get_filename(f)
        return
    def filename(self):
        return self.filename
    def get_filename(self,f):
        if(type(f)==str):
            filename=f
        elif(type(f)==file):
            filename=f.name
        else:
            filename=None
        return filename
    def read(self,f=None):
        if(f is None):
            if(self.filename is None):
                return
            else:   # Use internal filename
                filename=self.filename
        else:   # Change/set internal filename
            self.filename=self.get_filename(f)
            filename=self.filename
        data=[]
        try:
            with open(filename,'r') as F:
                for line in F:
                    data.append(line.split())
        except IOError as e:
            print("%s"%e)
            return
        F.close()
        for r in range(0,len(data)):
            for c in range(0,len(data[r])):
                data[r][c]=float(data[r][c])
        self.data=data
        self.x=[self.data[i][0] for i in range(0,len(self.data))]
        self.y=[self.data[i][1] for i in range(0,len(self.data))]
        return self.data
    def f00(self,x,a,b,c,d):
        return a*x**b*self.np.exp(-c*x)+d
    def cf00(self):
        popt,pcov=self.curve_fit(self.f00,self.x,self.y)
        self.y=self.f00(self.x,*popt)
        return self.y

我以交互模式将类粘贴到python中。然后尝试以下操作:

$ python
Python 2.7.14 (default, Oct 31 2017, 21:12:13)
[GCC 6.4.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

我粘贴上面显示的类,然后尝试以下操作:

>>> xy=XY("rot-03-05.dat")
>>> len(xy.x)
220
>>> len(xy.y)
220
>>> xy.cf00()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 56, in cf00
  File "/usr/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 751, in curve_fit
    res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
  File "/usr/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 383, in leastsq
    shape, dtype = _check_func('leastsq', 'func', func, x0, args, n)
  File "/usr/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 27, in _check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
  File "/usr/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 463, in func_wrapped
    return func(xdata, *params) - ydata
TypeError: 'XY' object is not callable
>>> xy.cf00
<bound method XY.cf00 of <__main__.XY object at 0x6ff5ea25fd0>>

我尝试从selff00()中取出cf00()。没用。

我尝试从实例中调用f00(),并且可以正常工作:

>>> xy=XY()
>>> xy.f00(1,1,1,1,1)
1.3678794411714423

我在其他地方使用了此曲线拟合功能,并且可以正常工作。现在,我正在尝试在一个类中实现它。

以下是独立的函数,当它们不属于类时可以使用:

def f00(x,a,b,c,d): return a*x**b*np.exp(-c*x)+d
def cf00(x,y):
    popt,pcov=curve_fit(f00,x,y,maxfev=1200000)
    return f00(x,*popt)

y1=cf00(x,y)

没问题。

2 个答案:

答案 0 :(得分:2)

因此,您正在类定义中导入from scipy.optimize import curve_fit,并且python将该名称绑定到了类名称空间,因此,当您调用self.curve_fit时,它是有效的,但请记住curve_fit函数在scipy内部定义。

当您致电self.method()时,实际上是: type(self).method(self),因此,当您调用self.curve_fit时,它将类XY作为第一个参数传递,并且它需要一个函数。

为解决此问题,我建议将导入内容放在文件的最顶部,然后仅调用curve_fit而不使用self

答案 1 :(得分:0)

这是一个很大的代码块,但我概述了您的代码中应修复的所有内容,包括注释:

import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
from io import TextIOWrapper # to check file-handle type
# Import modules at the global level, makes life easier

class XY(object):

    def __init__(self,f=None):
        self.filename = self.get_filename(f)
        self.data, self.x, self.y = self.read()
        # Don't return from __init__
        # return

    # This function is unnecessary
    # def file(self,f=None):
    #     self.filename=self.get_filename(f)
    #     return

    # This doesn't do anything, just access the attribute like instance.filename
    # def filename(self):
    #     return self.filename

    def get_filename(self,f):
        if isinstance(f, str): # use isinstance for type checking
            filename=f
        elif isinstance(f, TextIOWrapper):
            filename=f.name
        else:
            filename=None # I'd probably raise an exception here
        return filename


    def read(self): # the f param wasn't used otherwise
        # The whole block here was just a repeat of self.get_filename, no
        # need for it
        data=[]
        try:
            with open(filename,'r') as F:
                for line in F:
                    data.append(line.split())
        except IOError as e:
            # I would just let the exception happen and raise it
            print("%s"%e)
            raise
            # return # Don't just return None, you'll get weird behavior
        # F is already closed, that's what with does
        # F.close()
        for r in range(0,len(data)):
            for c in range(0,len(data[r])):
                data[r][c]=float(data[r][c])

        x = [self.data[i][0] for i in range(0,len(self.data))]
        y = [self.data[i][1] for i in range(0,len(self.data))]
        return data, x, y # It's generally bad form to assign self.attr outside of __init__

    def f00(self,x,a,b,c,d):
        return a*x**b*np.exp(-c*x)+d

    def cf00(self):
        popt, pcov = curve_fit(self.f00, self.x, self.y) # you don't need self.curve fit since it's now globally imported
        self.y=self.f00(self.x, *popt)
        return self.y # Not sure you need to return this, since you can just access it after the function is called

作为以后的参考,最好仅包含复制您面临的问题所需的内容,仅此而已。这样可以更轻松地找出问题所在。一个最小的工作示例可能如下所示:

import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np

def XY(object):
    def __init__(self):
        self.x = [float(a) for a in range(100)]
        self.y = [float(a) for a in range(100)]
        self.data = list(zip(self.x, self.y))

    def f00(self,x,a,b,c,d):
        return a*x**b*np.exp(-c*x)+d

    def cf00(self):
        popt, pcov = curve_fit(self.f00, self.x, self.y)
        return self.f00(self.x, *popt)

更容易发现问题所在