0

I'm not new to OOP but I'm quite a noobie when it comes to python, I'm working on a framework that should help in the development of my work but I'm getting confused by how to access methods.

I'm on Python 3.10

class Dialogue(EngineComponent):
    def __init__(self, name: str, directory=""):
        self.__scenes = []
        self.__directory = directory
        super().__init__(name, "dialogue", ".dialogue.json")

    def scene(self, tag: str):
        scene = Dialogue.__Scene(tag)
        self.__scenes.append(scene)
        return scene

    def export(self):
        dialogues = {
            "format_version": "1.17.0",
            "minecraft:npc_dialogue": {
                "scenes": []
            }
        }
        for scene in self.__scenes:
            dialogues["minecraft:npc_dialogue"]["scenes"].append(
                scene.__export())
        self.content(dialogues)
        return super().export(self.__directory)

    class __Scene():
        def __init__(self, tag: str):
            self.__buttons = []
            self.__tag = tag

        def properties(self, npc_name: str, text: str):
            self.__npc_name, self.__npc_display_name = RawText(npc_name)
            self.__text, self.__display_text = RawText(text)
            return self

        def button(self, button_name: str, commands: str or object):
            button = self.__Button(button_name, commands)
            self.__buttons.append(button)
            return button

        def __export(self):
            buttons = []
            for button in self.__buttons:
                buttons.append(button.__export())
            Language(f"npc_name.{self.__npc_name}={self.__npc_display_name}\n")
            Language(f"npc_text.{self.__tag}={self.__display_text}\n")
            return {
                "scene_tag": self.__tag,
                "npc_name": {"rawtext": [{"translate": f"npc_name.{self.__npc_name}"}]},
                "text": {"rawtext": [{"translate": f"npc_text.{self.__tag}", "with": ["\n"]}]},
                "buttons": buttons
            }

        class __Button():
            def __init__(self, button_name: str, commands: str or Function):
                self.__button_name = button_name
                if isinstance(commands, Function):
                    self.__commands = f"function {commands.get_path()}"
                else:
                    self.__commands = commands

            def __export(self):
                Language(f"{self.__button_name}={self.__button_name}\n")
                return {
                    "name": self.__button_name,
                    "commands": [
                        self.__commands
                    ]
                }

I have written the class above to help with the generation of files, and actual usage of that class should be

d0 = Dialogue("my_dialogue")
scene0 = d0.scene("hello").properties("Jake","Hello traveler!\\nLooking for some tips?").button("Get Tips","/say tips")
d0.export()

Everything worked fine when I write all the export methods as export()

But I want to prevent people from using the inner classes export() methods for the __Scene and __Button so I'm following the PEP8 or so I read on other posts that I should just switch export() to __export(). It can still be used but someone familiar with python knows better not to

But when I do that I get this error AttributeError: '__Scene' object has no attribute '_Dialogue__export'

for scene in self.__scenes:
            dialogues["minecraft:npc_dialogue"]["scenes"].append(
                scene.__export())

And I can't figure out why?? I've just changed the name of the method and the way how I call it, why is it not working as intended?

I'm also using chained method calls as you can see in properties() and button() but also for a lot of other classes where I have so many methods. I'm wondering if there's a way to limit the reusability of each method but still allow chained calls for unused ones?

  • 1
    See https://stackoverflow.com/questions/45288973/double-underscore-in-python#45289067 – Michael Butscher Dec 05 '21 at 14:21
  • I get how the double underscore works in the scope of an object, but if you check the code again, you can that I'm accessing __export() from a __Scene object. How should I go about accessing __Scene's method if scene.__export() automatically switches to scene.__Dialogue.__export()? – Yasser Benfoughal Dec 05 '21 at 15:27
  • It depends on the location of the code how the name mangling works. In your case the "__export" call is in "Dialogue" class. You can either do the right name mangling manually or don't use the double underscore in the function name at all. Latter is recommended because you currently try to call a private function from another class (I know that this would work for other languages). – Michael Butscher Dec 05 '21 at 18:28
  • You would probably be fine to just use a single underscore so as to avoid name mangling. Part of the philosophy of python is "we are all adults here". Truly private attributes do noy exist, but using an underscore should be enough of a signal to tell clients not to access that attribute directly. – Luke Nelson Dec 07 '21 at 02:02

0 Answers0