0

This is my first program after a bunch of small tutorials, and my file explorer works wonderfully. Did some custom icons, thumbnail for images, and I can scroll, multyselect stuff and browse with my icons. Originally it took 3.2 seconds to open/resize/blend-paste/display 81 pictures(100x100), and managed to bring it to 1.5 seconds. Multithreading will come soon :) I got rid of all my globals, to learn it the proper way, and now I want to understand classes more, I am happy that I made it work anyhow, but what is the correct way to initialize it in init?

I create an instance with:

folder_left = Folder(folder_left_settings.last_directory)

when I change the Folder:

folder_left.elements_create(values["-FOLDER-"])
folder_left.directory = values["-FOLDER-"]
folder_left_settings.last_directory = values["-FOLDER-"]
folder_left_settings.write_to_ini()
class Folder:
    def __init__(self, directory):
        self.directory = directory
        self.elements_create(directory)

    def elements_create(self, directory):
        self.element_name = []
        self.element_image_data = []
        self.element_is_selected = []
        self.element_is_type = []
        self.list_of_indexes_marked_elements = []
        if directory:
            for file in os.listdir(directory):
                if os.path.isdir(os.path.join(directory,file)):
                    self.element_name.append(file)
                    self.element_is_selected.append(False)
                    self.element_image_data.append(graphics_FolderIcon)
                    self.element_is_type.append("Icon")
                if file.endswith((".gif", ".png", ".jpg")):
                    self.element_name.append(file)
                    self.element_is_selected.append(False)
                    self.element_is_type.append("Image")
                    try:
                        self.element_image_data.append(
                            image.convert_to_bytes(os.path.join(directory, file), (100, 100), fill_blanc_color=(90, 105, 121)))
                    except:
                        sg.popup(f"Error reading Image:{self.element_name}")
                        self.element_image_data.append(empty_image)

this tread Instance attribute attribute_name defined outside __init__ suggested to initialize them with None in init

I tried several combinations of:

def __init__(self, directory ***self.element_name=None***):
***self.element_name=None***
***self.element_name = []***
***self.element_name = element_name***

    def elements_create(self, directory):
        ***self.element_name = []***

of course not all together, just the combinations(with and without)....nothing works, and my elements end up beeing None, or other exceptions. I know that I can do everything INSIDE ini directly and just overwrite create my instance if the folder changes, but I thought this would be better and proper. THX ALOT!!!

(I don't really understand the return 2nd answer with return as solution. It would make it pretty unreadable if I cannot append directly to the lists, since if understanding correctly, I would use placeholder objects in my method, so I can return all in one line. There must be a simple solution I don't see.)

Leonick
  • 45
  • 7

1 Answers1

1

This IDE recommendation is for organizing your code only, and should not affect how it works. However, it exists to remind you to put just the behavior necessary for instantiate your class in __init__, if your class has data that does not depend on initialization you can put it before __init__. For example:

class Folder:
    element_name = []
    element_image_data = []
    element_is_selected = []
    element_is_type = []
    list_of_indexes_marked_elements = []

    def __init__(self, directory):
        self.directory = directory
        self.elements_create(directory)

    def elements_create(self, directory):
        ...

Or you can also take this other approach, which may be more suitable in some cases:

class Folder:
    def __init__(self, directory):
        self.directory = directory

    @classmethod
    def create_instance(cls, directory):
        folder = cls(directory)
        folder.element_name = []
        folder.element_image_data = []
        folder.element_is_selected = []
        folder.element_is_type = []
        folder.list_of_indexes_marked_elements = []
        return folder

folder = Folder.create_instance("directory")
print(dir(folder))

Output:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'create_instance', 'directory', 'element_image_data', 'element_is_selected', 'element_is_type', 'element_name', 'list_of_indexes_marked_elements']
  • wow thx João. Wow I never tried to put it into the class directly!! Of course I know that it is just a warning, but I figured that it was POSSIBLE not the correct way, since I also read in other threads, that all attributes SHOULD be in __init__. And I want to learn to do it correctly. I have looked into @classmethod as well, but doesn't this produce a lot of overhead I don't need? Solution #1 & #2 also violate that etiquette rule, to put everything into __init__. – Leonick Nov 04 '22 at 13:20
  • @Leonick Yes you're right, most of the time it's better to declare everything in init, but it really depends on what you want to do. Sometimes you want to have attributes that are from your class and attributes that are from your instance, in which case you would put them separately, as I showed above. The second way has some uses, but they are rarer (if you want to see more, check out this design pattern https://refactoring.guru/design-patterns/factory-method). As you said that you had seen that you should declare it in init, I thought you were looking for other ways to do it too. – João Bonfim Nov 04 '22 at 13:47
  • thx again...this is a really good link. All the beginner tutorials about classes have all the same format,...student age,bla bla..initialised together...not practicable for real life...since most cases I guess are more complicated. Also saw a performance comparisson with classmethod, and I think init times were alot higher, if I am not mistaken. Also wondering that I couldn't find a Win-like fileexplorer, someone did with python...hard to believe. When I deactivate thumbnail cache in Win, mine is alot faster than Win. Not even multithreading implemented,..that wil also be a fun lesson. – Leonick Nov 04 '22 at 14:21