TypeError: объект «имя класса» не может быть вызван

Я работаю над классом для работы с наборами данных "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>>

Я пытался убрать self из f00() и 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)

Нет проблем.

Итак, проблема в том, когда вы берете selfвне из определения cf00?

C.Nivs 05.04.2019 21:31

Это содержит массу ненужного кода, который можно было бы обрезать, чтобы сделать этот MCVE

C.Nivs 05.04.2019 21:32

Кроме того, __init__ никогда не должен содержать оператор return.

C.Nivs 05.04.2019 21:33

Я не знаю, имеет ли это значение, но обычно мы не делаем импорт как часть определения класса. Обычно это делается в начале модуля. Иногда импорт выполняется внутри функции (или метода).

hpaulj 05.04.2019 21:36

Нет. Я взял "я", чтобы посмотреть, устранит ли это проблему. Это не так.

Mannix 05.04.2019 21:37

Я рекомендую прочитать о классы

C.Nivs 05.04.2019 21:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
6
486
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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

Это работает. Я также узнал, что мне нужно использовать массивы numpy вместо списков для подбора кривой.

Mannix 05.04.2019 21:58

Хорошая заметка о self.curve_fit. То, что должен вызывается, это XY.curve_fit, поскольку оно импортируется на уровне класса, а не на уровне экземпляра.

C.Nivs 05.04.2019 22:04

Это большой блок кода, но я указал, что все должно быть исправлено в вашем коде, включая комментарии:

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)

Гораздо проще определить, что идет не так

Другие вопросы по теме