Как исправить ошибку с missing 1 required positional argument: 'self'?

Я написал код для поиска обалютно одинаковых фото, сейчас пытаюсь его оптимизировать, решил сделать через класс, чтоб удобней было работать с multiprocessing и в следствии чего вылезла ошибка: TypeError: calculating() missing 1 required positional argument: 'self'

from PIL import Image
import glob
import os
from datetime import datetime
from numpy import array, delete, append
# from numpy import delete, append
from multiprocessing import Process, set_start_method

filename_list = glob.glob('C:/Users/administrator/Desktop/)/*')

images = filename_list
used_images = []
bad_image = []
true_bad_images = []
good_image = []
pic_image = []
pic_image1 = []

images = array(images)
used_images = array(used_images)
bad_image = array(bad_image)
true_bad_images = array(true_bad_images)
good_image = array(good_image)
pic_image = array(pic_image)
pic_image1 = array(pic_image1)


class lets_do_this:
    def __init__(self):
        self.image1 = Image.open(images[self.j])
        self.image = Image.open(images[self.i])
        self.width1 = self.image1.size[0]
        self.width = self.image.size[0]
        self.height1 = self.image1.size[1]
        self.height = self.image.size[1]
        self.pix1 = self.image1.load()
        self.pix = self.image.load()

    def calculating(self):
        for i in range(len(images)):
            self.i = i
            # print(f'{i}')
            for j in range(len(images)):
                self.j = j
                # print(f'{i}.{j}')
                if i != j:
                    if self.width == self.width1 and self.height == self.height1:
                        set_start_method('spawn')
                        p1 = Process(target=lets_do_this.first_step)
                        p1.start()
                        p1.join()
                    else:
                        if len(good_image) != 0:
                            for m in range(len(good_image)):
                                if good_image[m] != images[i] and m == len(good_image) - 1:
                                    append(good_image, images[i])
                        else:
                            append(good_image, images[i])

                    # pic_image.clear()
                    # pic_image1.clear()

                    delete(pic_image, [m for m in range(len(pic_image))], axis=None)
                    delete(pic_image1, [m for m in range(len(pic_image1))], axis=None)

            append(used_images, images[i])

            print(good_image, bad_image)
            print(datetime.now() - start)
            break

        # pic_image.clear()
        # pic_image1.clear()

        delete(pic_image, [m for m in range(len(pic_image))], axis=None)
        delete(pic_image1, [m for m in range(len(pic_image1))], axis=None)

        print(f'--------------------')

        p1 = Process()
        p1.start()
        p1.join()

def first_step(self):
    i = self.i
    for k in range(self.width):
        for l in range(self.height):
            append(pic_image, self.pix[k, l])
    for k1 in range(self.width1):
        for l1 in range(self.height1):
            append(pic_image1, self.pix1[k1, l1])

    if pic_image == pic_image1:
        p1 = Process(target=lets_do_this.second_step)
        p1.start()
        p1.join()
    else:
        if len(good_image) != 0:
            for m in range(len(good_image)):
                if good_image[m] != images[i] and m == len(good_image) - 1:
                    append(good_image, images[i])
        else:
            append(good_image, images[i])

def second_step(self):
    i = self.i
    if len(bad_image) != 0:
        if len(used_images) != 0:
            append(bad_image, images[i])
        else:
            append(bad_image, images[i])
    else:
        if len(used_images) != 0:
            append(bad_image, images[i])
        else:
            append(bad_image, images[i])
        if len(good_image) != 0:
            for m in range(len(good_image)):
                if good_image[m] != images[i] and m == len(good_image) - 1:
                    append(good_image, images[i])
        else:
            append(good_image, images[i])

def third_step():
    if bad_image is not None:
        for i in range(len(bad_image)):
            for j in range(len(bad_image)):
                if i != j:
                    image = Image.open(images[i])
                    image1 = Image.open(images[j])
                    width = image.size[0]
                    width1 = image1.size[0]
                    height = image.size[1]
                    height1 = image1.size[1]

                    if width == width1 and height == height1:
                        if len(true_bad_images) != 0:
                            for a in range(len(true_bad_images)):
                                if len(used_images) != 0:
                                    for b in range(len(used_images)):
                                        if true_bad_images[a] == used_images[b]:
                                            pass
                                        elif b == len(used_images) and a == len(true_bad_images):
                                            append(true_bad_images, bad_image[i])
                                            append(used_images, bad_image[j])
                                else:
                                    if true_bad_images[a] == bad_image[i]:
                                        pass
                                    elif a == len(true_bad_images):
                                        append(true_bad_images, bad_image[i])
                                        append(used_images, bad_image[j])

                        else:
                            append(true_bad_images, bad_image[i])
                            if len(used_images) != 0:
                                for a in range(len(used_images)):
                                    if used_images[a] != bad_image[j]:
                                        append(used_images, bad_image[j])
                            else:
                                append(used_images, bad_image[j])

    end()


start = datetime.now()
if __name__ == '__main__':
    set_start_method('spawn')
    p_start = Process(target=lets_do_this.calculating)
    p_start.start()
    p_start.join()


def end():
    true_good_images = good_image[:]

    true_good_images = array(true_good_images)

    for i in range(len(good_image)):
        for j in range(len(true_bad_images)):
            if good_image[i] == true_bad_images[j]:
                delete(true_good_images, j)

    for i in range(len(true_bad_images)):
        if len(true_bad_images) != 0:
            if os.path.isfile(true_bad_images[i]):
                os.remove(true_bad_images[i])

    print(datetime.now() - start)

    print(f'\nbad image: {true_bad_images}\n good image: {good_image}\n true good images: {true_good_images}')

    print(f'success :)')

это лишь часть кода, но пока только тут и ошибка, если надо могу выслать весь код), помогите пожалуйста


Ответы (1 шт):

Автор решения: CrazyElf

Поскольку first_step и second_step - это методы экземпляра класса, то попробуйте вызывать их от экземпляра класса, а не просто от класса:

p1 = Process(target=self.first_step)
...
p1 = Process(target=self.second_step)
...
p_start = Process(target=lets_do_this().calculating)

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

p1 = Process(target=lambda: self.first_step())
...
p1 = Process(target=lambda: self.second_step())
...
p_start = Process(target=lambda: lets_do_this().calculating())

Но вообще многопоточность не такая уж простая штука. Процессы работают с копией данных того процесса, из которого вы их вызываете. Поэтому всё, что вы меняете в этих дополнительных процессах, там же и остаётся, в основном процессе данные остаются прежние, не зависимые от изменений в порождённых процессах.

Так что от ошибки вы может быть и избавитесь, а вот от проблем в архитектуре программы - скорее всего нет. Придётся её капитально переосмысливать.

Если хотите правильно работать с процессами, то подумайте, что в них нужно передавать и что получать из них обратно. Передачу нужно будет сделать в явном виде, а не надеяться на то, что всё и так само передастся. Если ничего не делать, то туда передастся слишком много, а обратно не передастся ничего. Поэтому передаваемые данные нужно минимизировать, иначе выигрыша от многопроцессности не будет, весь выигрыш съест сериализация и передача данных сначала в процесс, а потом обратно. И да, нужно будет в явном виде передать данные в процесс и получить их в явном виде обратно.

Так что скорее всего проще использовать multiprocessing.Pool, в него проще передавать данные и получать их обратно после обработки.

→ Ссылка