Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Cyborg)
  • No Skin
Collapse
Brand Logo

CIRCLE WITH A DOT

  1. Home
  2. Uncategorized
  3. Can someone explain this #Python import behavior

Can someone explain this #Python import behavior

Scheduled Pinned Locked Moved Uncategorized
python
21 Posts 8 Posters 0 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ehmatthes@fosstodon.orgE ehmatthes@fosstodon.org

    @bmispelon Then I ran c.py in a VS Codium debugger session, watching A.

    - A starts as undefined (everything does).
    - After the first line of a.py, A is 1, but I think that VS Codium is actually reporting a.A.
    - The import in a is hit, and A goes to undefined. I think VSC is showing b.A.
    - b's import runs, and A is 1. I think that's b.A.
    - The second line of b is run, and A is 2.
    - Execution goes back to c, where the value of A is 2.

    ehmatthes@fosstodon.orgE This user is from outside of this forum
    ehmatthes@fosstodon.orgE This user is from outside of this forum
    ehmatthes@fosstodon.org
    wrote last edited by
    #12

    @bmispelon Here's my VSCodium session:

    1 Reply Last reply
    0
    • bmispelon@mastodon.socialB bmispelon@mastodon.social

      Can someone explain this #Python import behavior?
      I'm in a directory with 3 files:

      a.py contains `A = 1; from b import *`
      b.py contains `from a import *; A += 1`
      c.py contains `from a import A; print(A)`

      Can you guess and explain what happens when you run `python c.py`?

      ehmatthes@fosstodon.orgE This user is from outside of this forum
      ehmatthes@fosstodon.orgE This user is from outside of this forum
      ehmatthes@fosstodon.org
      wrote last edited by
      #13

      @bmispelon Can you share the real-world motivation for this question at some point?

      bmispelon@mastodon.socialB 1 Reply Last reply
      0
      • ehmatthes@fosstodon.orgE ehmatthes@fosstodon.org

        @bmispelon Can you share the real-world motivation for this question at some point?

        bmispelon@mastodon.socialB This user is from outside of this forum
        bmispelon@mastodon.socialB This user is from outside of this forum
        bmispelon@mastodon.social
        wrote last edited by
        #14

        @ehmatthes A very old Django project whose multiple settings files were importing from each other, leaving me very confused for a bit πŸ˜…

        I definitely would not recommend writing actual code that looks like this!

        ehmatthes@fosstodon.orgE 1 Reply Last reply
        0
        • bmispelon@mastodon.socialB bmispelon@mastodon.social

          @ehmatthes A very old Django project whose multiple settings files were importing from each other, leaving me very confused for a bit πŸ˜…

          I definitely would not recommend writing actual code that looks like this!

          ehmatthes@fosstodon.orgE This user is from outside of this forum
          ehmatthes@fosstodon.orgE This user is from outside of this forum
          ehmatthes@fosstodon.org
          wrote last edited by
          #15

          @bmispelon

          > whose multiple settings files were importing from each other

          You are not the only one who would be confused, please do not mention this in office hours

          1 Reply Last reply
          0
          • bmispelon@mastodon.socialB bmispelon@mastodon.social

            Can someone explain this #Python import behavior?
            I'm in a directory with 3 files:

            a.py contains `A = 1; from b import *`
            b.py contains `from a import *; A += 1`
            c.py contains `from a import A; print(A)`

            Can you guess and explain what happens when you run `python c.py`?

            pawamoy@fosstodon.orgP This user is from outside of this forum
            pawamoy@fosstodon.orgP This user is from outside of this forum
            pawamoy@fosstodon.org
            wrote last edited by
            #16

            @bmispelon

            Got it! Did it in my head then verified with an interpreter πŸ™‚

            There's nothing weird here. Python executes stuff sequentially, so:

            - in πŸ˜„ from a import A
            - in a: A = 1
            - in a: from b import *
            - in b: from a import * (so we have A = 1 in b)
            - in b: A += 1 (so we have A = 2 in b)
            - in a: finishing previous import, so we now have A = 2 in a
            - in πŸ˜„ finishing previous import, so we now have A = 2 in C
            - in πŸ˜„ print(A) -> 2!

            pawamoy@fosstodon.orgP 1 Reply Last reply
            0
            • bmispelon@mastodon.socialB bmispelon@mastodon.social

              @jonafato Interesting suggestion for a fix! What happens then if all the `from ... import *` are replaced by `from ... import A`?

              jonafato@mastodon.socialJ This user is from outside of this forum
              jonafato@mastodon.socialJ This user is from outside of this forum
              jonafato@mastodon.social
              wrote last edited by
              #17

              @bmispelon That would result in the same original behavior, since `__all__` controls the import behavior of `*` but not of individual variables (though I think I have seen projects that allow you to turn that kind of thing into an error via name mangling or some other hack under the hood).

              1 Reply Last reply
              0
              • pawamoy@fosstodon.orgP pawamoy@fosstodon.org

                @bmispelon

                Got it! Did it in my head then verified with an interpreter πŸ™‚

                There's nothing weird here. Python executes stuff sequentially, so:

                - in πŸ˜„ from a import A
                - in a: A = 1
                - in a: from b import *
                - in b: from a import * (so we have A = 1 in b)
                - in b: A += 1 (so we have A = 2 in b)
                - in a: finishing previous import, so we now have A = 2 in a
                - in πŸ˜„ finishing previous import, so we now have A = 2 in C
                - in πŸ˜„ print(A) -> 2!

                pawamoy@fosstodon.orgP This user is from outside of this forum
                pawamoy@fosstodon.orgP This user is from outside of this forum
                pawamoy@fosstodon.org
                wrote last edited by
                #18

                @bmispelon by the way I'm not sure to understand why the circular import works. I think Python has special handling for some cases where it's able to tell the circular import is "safe" somehow (like "a is almost finished, there's only * to import from b", meaning b can import from a again, and when b is finisehd a is updated again with any symbols declared in b). Tried to find an actual answer in the past but didn't find anything. Maybe should read the sources!

                pawamoy@fosstodon.orgP 1 Reply Last reply
                0
                • pawamoy@fosstodon.orgP pawamoy@fosstodon.org

                  @bmispelon by the way I'm not sure to understand why the circular import works. I think Python has special handling for some cases where it's able to tell the circular import is "safe" somehow (like "a is almost finished, there's only * to import from b", meaning b can import from a again, and when b is finisehd a is updated again with any symbols declared in b). Tried to find an actual answer in the past but didn't find anything. Maybe should read the sources!

                  pawamoy@fosstodon.orgP This user is from outside of this forum
                  pawamoy@fosstodon.orgP This user is from outside of this forum
                  pawamoy@fosstodon.org
                  wrote last edited by
                  #19

                  @bmispelon OK no it's much simpler, module a is simply partially initialized. By the time b imports it, it's not re-executed since it exists in sys.modules, and b imports every existing (yet) symbols within A. from a import A would work too.

                  1 Reply Last reply
                  0
                  • bmispelon@mastodon.socialB bmispelon@mastodon.social

                    @treyhunner Tagging you on this since it might qualify as a #Pythonoddity

                    treyhunner@mastodon.socialT This user is from outside of this forum
                    treyhunner@mastodon.socialT This user is from outside of this forum
                    treyhunner@mastodon.social
                    wrote last edited by
                    #20

                    @bmispelon This is absolutely a Python oddity. I guessed incorrectly. I understand why I guessed incorrectly now that I look back at the code... I'm not sure any Python oddity has stress testeded my mental model of Python's import system as much as this one.

                    1 Reply Last reply
                    0
                    • bmispelon@mastodon.socialB bmispelon@mastodon.social

                      Can someone explain this #Python import behavior?
                      I'm in a directory with 3 files:

                      a.py contains `A = 1; from b import *`
                      b.py contains `from a import *; A += 1`
                      c.py contains `from a import A; print(A)`

                      Can you guess and explain what happens when you run `python c.py`?

                      stylus@social.afront.orgS This user is from outside of this forum
                      stylus@social.afront.orgS This user is from outside of this forum
                      stylus@social.afront.org
                      wrote last edited by
                      #21

                      @bmispelon

                      $ echo 'A = 1; print("A1"); from b import A; print("A2")' > a.py
                      $ echo 'print("B1"); from a import A; print("B2"); A += 1' > b.py
                      $ python -c 'from a import A; print(A)'
                      A1
                      B1
                      B2
                      A2
                      2

                      I added several prints so that it's possible to tell what order code is executed, and changed import * to import A because I think it improves clarity without changing the behavior.

                      • The main program runs
                      • It encounters an import of a so it starts executing the content of a.py in a newly created a module
                      • It sets A.a=1 via the assignment statement in a.py
                      • It encounters an import of b so it starts executing the content of b.py in a newly created b module
                      • It sets b.A=1 by from...import
                      • It adds 1 to b.A so that b.A is now equal to 2
                      • Execution reaches the end of b.py so it returns to a.py
                      • a.py sets a.A to 2 by from...import
                      • Execution reaches the end of a.py so it returns to the main program.
                      • The main program sets __main__.A to 2 by from ...import
                      • The value of A is printed (2)
                      1 Reply Last reply
                      0
                      • R relay@relay.an.exchange shared this topic
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups