0

I know I'm being dense and I know what the problem is but I can't seem to figure out how to fix it.

testcode.py

import t2

class t1:
    saved = 0
    @classmethod
    def set_class(cls, number):
        t1.saved = number

not_in_main = t1

if __name__ == "__main__":
    not_in_main.set_class(6)
    used_everywhere = t1

    used_everywhere.set_class(4)
    t2.f1()

and then in t2.py

import testcode


def f1():
    print(f'not_in_main: {testcode.not_in_main.saved}')
    print(f'got here: {testcode.used_everywhere.saved}')

Now the output after running python testcode.py will be

not_in_main: 0
AttributeError: module 'testcode' has no attribute 'used_everywhere'

So not_in_main has two different instances one in the main scope and one module scope. Used_everywhere is also in the main scope but another module can't see in instance.

I've looked at many of the scoping issues but I don't see how to fix this. What am I doing wrong?

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
cryptoref
  • 413
  • 1
  • 7
  • 17
  • To be clear, the results of the execution are from running testcode. I understand that if one ran T2 only then the __main__ will not run. What I want to happen is to have the functions in T2 have access to a single instance of t1. What I see from the output in T2 is that it looks like different instances. If they were pointing at the exact same object, then you shouldn't see different values in the print. In T2 the testcode.not_in_main.saved SHOULD be 6, it is 0. testcode.used_everywhere.saved SHOULD be 4 but I get the attribute error. – cryptoref Feb 12 '22 at 02:38
  • 1
    Ah. Yes, this is a wart in the Python import system. So you do `python testcode.py`. The module is loaded and saved to `sys.modules` as `__main__`. Then when you use `t2`, you `import testcode`, the import caching mechanism looks for `testcode` in `sys.modules`, doesn't find it, **then re-imports `testcode` as a completely seperate module**. Yeah you have to be careful with this one – juanpa.arrivillaga Feb 12 '22 at 02:41
  • I WANT to be careful, I'm just too dense to know HOW to be careful :) I can see what's happening I just don't understand how to get it right. – cryptoref Feb 12 '22 at 02:43
  • They really should have picked a different way of distinguishing the entry point module instead of the whole `__main__` thing, but we're stuck with this design, with all its awkward side effects. This is a Python-specific reason to avoid circular imports - if you don't have circular imports, you can't end up re-importing the entry point module. – user2357112 Feb 12 '22 at 02:44
  • Well, see, this is a circular dependency, which you should always be weary of in Python, due to its dynamic nature (in statically compiled languages this is less of an issue). Often it will fail with an error, sometimes it won't, and in this particular case, it leads to very unexpected behavior. Generally, you should **avoid circular imports** – juanpa.arrivillaga Feb 12 '22 at 02:45
  • @user2357112supportsMonica there *must* be a duplicate of this somewhere – juanpa.arrivillaga Feb 12 '22 at 02:45
  • So how do I avoid the issue when module 1 declares a class, module 2 uses that class but needs a callback to module 1. Stick them in one module? Is that the pythonic way to deal with this? I just was trying to keep the classes in separate modules to avoid one really big module. – cryptoref Feb 12 '22 at 02:47
  • @cryptoref generally yes. The 1-class-per-module is not really a thing in Python. But it really depends on what you mean exactly by "but needs a callback to module 1". There are other ways to get it done. – juanpa.arrivillaga Feb 12 '22 at 02:49
  • The goal was to separate a middle layer of database and computations from the display layer. Respond to UI, do some op, change the display based on new DB items, display status bar ... So the basic split was UI from the middle layer but there are references to state or other variables or routines. – cryptoref Feb 12 '22 at 02:52

1 Answers1

0

The fix for this circular issue was to move the class def and creation of the module variable to a file other than where main is. The project now just has main in the a module and most all other code in a separate file.

Breakpoints on the not_in_main show it only being instantiated once as opposed to twice as in the listed code.

When necessary, as in generated code for the UI, that is in a separate module, the import of the module where not_in_main is declared does not cause a circular reference and the fields are properly filled out.

Thanks to @junpa.arrivillaga for the pointers and hints to put me on the right path.

cryptoref
  • 413
  • 1
  • 7
  • 17