So this is my very first time in this site. I have written this very basic Python code witj PyQt5 to create a Memory Game. As I am not very familiar with OOP (but I'm trying to be!), I hope somebody could point me to where I could improve my game.

As it stands, the whole thing is working but it lacks of a pretty template (this is something I am going to improve in a second phase). What I am more interested in right now is to understand if my code could be better organized somehow (e.g. by splitting it into different classes/subclasses, instead of the many methods present).

The game works like this:

 1. the user chooses a folder of (JPG) images;
 2. a grid with all the images is formed, but each image is covered by the "back.jpg" image (it should stay in the same folder as the code)
 3. the game starts

Basically I am kind of doing everything using images in a Qgridlayout, which are put in buttons with event listeners. When an "onclick" signal is emitted, the `self.status` attribute is analyzed and the game is restarted or goes on according to that.

One last thing: the cards (images) are not shuffled right now, I still need to implement this feature (otherwise the game would be completely boring...).

Here is the code, thanks in advance for any suggestion:

    import os, sys, glob, math
    from PyQt5.QtWidgets import (QMainWindow, QWidget,
        QGridLayout, QPushButton, QApplication,
        QAction, QFileDialog, QLabel)
    from PyQt5.QtGui import QPixmap, QIcon
    
    class MemoryGame(QMainWindow):
        def __init__(self):
            super().__init__()
            self.back_card = r'./back.jpg'
            self.status = []
            self.initUI()
    
        def initUI(self):
            self.statusBar()
    
            openFile = QAction('Open', self)
            openFile.setShortcut('Ctrl+O')
            openFile.setStatusTip('Search image folder')
            openFile.triggered.connect(self.showDialog)
    
            menubar = self.menuBar()
            self.fileMenu = menubar.addMenu('&File')
            self.fileMenu.addAction(openFile)
    
            self.gridWidget = QWidget(self)
            self.gridLayout = QGridLayout(self.gridWidget)
            self.setCentralWidget(self.gridWidget)
    
            self.setGeometry(300, 300, 350, 300)
            self.setWindowTitle('Memory Game!')
            self.show()
    
        def showDialog(self):
            """Seacrh for a folder of images, and create two dictionaries:
            - one with grid_position : image
            - one with grid_position : back_card"""
            folder = str(QFileDialog.getExistingDirectory(self, "Select Directory",
                '.', QFileDialog.ShowDirsOnly))
    
            self.list_images(folder)
            if self.n_img > 0:
                self.fill_dict(self.images) # create the grid_position:image Dict
                self.empty_dict()
                self.init_grid()
    
        def list_images(self, folder):
            """List the (JPEG) images within the selected folder"""
            images = glob.glob(os.path.join(folder, '*.jpg'))
            n_img = len(images)
            
            self.images = images
            self.n_img = n_img
    
        def fill_dict(self, images):
            grid_cell = images * 2
            self.card_dict = {}
            n_cols = math.ceil(math.sqrt(len(grid_cell)))
            n_rows = math.ceil(math.sqrt(len(grid_cell)))
            positions = [(i,j) for i in range(n_cols) for j in range(n_rows)]
            for p, cell in zip(positions, grid_cell):
                if cell == '':
                    continue
                self.card_dict[p] = cell
    
        def empty_dict(self):
            # copy the card_dict to make a back_dict (with the back_card)
            self.back_dict = dict(self.card_dict)
            for k, v in self.back_dict.items():
                self.back_dict[k] = self.back_card
            
        def init_grid(self):
            """Initialize the grid according to the number of images
            found in the selected folder."""
    
            for pos, img in self.back_dict.items():
                btn = QPushButton(self)
                btn.clicked.connect(self.buttonClicked)
                pixmap = QPixmap(self.back_dict[pos])
                scaled = pixmap.scaled(pixmap.width()/3, pixmap.height()/3) # can be done better....
                btn.setIcon(QIcon(scaled))
                btn.setIconSize(scaled.rect().size())
                btn.setFixedSize(scaled.rect().size())
                del(pixmap)
    
                self.gridLayout.addWidget(btn, *pos)
                
        def turn_card(self, btn, location):
            """When a button (image) is clicked, turn the card."""
    
            if len(self.status) == 0 or len(self.status) % 2 == 0 or self.card_dict[location] in self.status:
                self.status.append(self.card_dict[location])
                pixmap = QPixmap(self.card_dict[location])
                scaled = pixmap.scaled(pixmap.width()/3, pixmap.height()/3)
                btn.setIcon(QIcon(scaled))
                btn.setIconSize(scaled.rect().size())
                btn.setFixedSize(scaled.rect().size())
                del(pixmap)
            else:
                self.status = []
                self.init_grid()
                
        def buttonClicked(self):
            button = self.sender()
            idx = self.gridLayout.indexOf(button)
            location = self.gridLayout.getItemPosition(idx)
            # print ("Button", button, "at row/col", location[:2])
            self.turn_card(button, location[:2])
            
    if __name__ == '__main__':
        
        app = QApplication(sys.argv)
        ex = MemoryGame()
        sys.exit(app.exec_())