How can I open two consoles from a single script

前端 未结 6 1135
渐次进展
渐次进展 2020-11-29 05:32

Apart from the scripts own console (which does nothing) I want to open two consoles and print the variables con1 and con2 in different con

相关标签:
6条回答
  • 2020-11-29 05:58

    I don't know if it suits you, but you can open two Python interpreters using Windows start command:

    from subprocess import Popen
    p1 = Popen('start c:\python27\python.exe', shell=True)
    p2 = Popen('start c:\python27\python.exe', shell=True)
    

    Of course there is problem that now Python runs in interactive mode which is not what u want (you can also pass file as parameter and that file will be executed).

    On Linux I would try to make named pipe, pass the name of the file to python.exe and write python commands to that file. 'Maybe' it will work ;)

    But I don't have an idea how to create named pipe on Windows. Windows API ... (fill urself).

    0 讨论(0)
  • 2020-11-29 05:58

    pymux

    pymux gets close to what you want: https://github.com/jonathanslenders/pymux

    Unfortunately it is mostly a CLI tool replacement for tmux and does not have a decent programmatic API yet.

    But hacking it up to expose that API is likely the most robust option if you are serious about this.

    The README says:

    Parts of pymux could become a library, so that any prompt_toolkit application can embed a vt100 terminal. (Imagine a terminal emulator embedded in pyvim.)

    0 讨论(0)
  • 2020-11-29 06:02

    If you don't want to reconsider your problem and use a GUI such as in @Kevin's answer then you could use subprocess module to start two new consoles concurrently and display two given strings in the opened windows:

    #!/usr/bin/env python3
    import sys
    import time
    from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE
    
    messages = 'This is Console1', 'This is Console2'
    
    # open new consoles
    processes = [Popen([sys.executable, "-c", """import sys
    for line in sys.stdin: # poor man's `cat`
        sys.stdout.write(line)
        sys.stdout.flush()
    """],
        stdin=PIPE, bufsize=1, universal_newlines=True,
        # assume the parent script is started from a console itself e.g.,
        # this code is _not_ run as a *.pyw file
        creationflags=CREATE_NEW_CONSOLE)
                 for _ in range(len(messages))]
    
    # display messages
    for proc, msg in zip(processes, messages):
        proc.stdin.write(msg + "\n")
        proc.stdin.flush()
    
    time.sleep(10) # keep the windows open for a while
    
    # close windows
    for proc in processes:
        proc.communicate("bye\n")
    

    Here's a simplified version that doesn't rely on CREATE_NEW_CONSOLE:

    #!/usr/bin/env python
    """Show messages in two new console windows simultaneously."""
    import sys
    import platform
    from subprocess import Popen
    
    messages = 'This is Console1', 'This is Console2'
    
    # define a command that starts new terminal
    if platform.system() == "Windows":
        new_window_command = "cmd.exe /c start".split()
    else:  #XXX this can be made more portable
        new_window_command = "x-terminal-emulator -e".split()
    
    # open new consoles, display messages
    echo = [sys.executable, "-c",
            "import sys; print(sys.argv[1]); input('Press Enter..')"]
    processes = [Popen(new_window_command + echo + [msg])  for msg in messages]
    
    # wait for the windows to be closed
    for proc in processes:
        proc.wait()
    
    0 讨论(0)
  • 2020-11-29 06:05

    I used jfs' response. Here is my embellishment/theft of jfs response. This is tailored to run on Win10 and also handles Unicode:

    # https://stackoverflow.com/questions/19479504/how-can-i-open-two-consoles-from-a-single-script
    import sys, time, os, locale
    from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE
    
    class console(Popen)  :
        NumConsoles = 0
        def __init__(self, color=None, title=None):
            console.NumConsoles += 1
    
            cmd = "import sys, os, locale"
            cmd += "\nos.system(\'color " + color + "\')" if color is not None else ""
            title = title if title is not None else "console #" + str(console.NumConsoles)
            cmd += "\nos.system(\"title " + title + "\")"
            # poor man's `cat`
            cmd += """
    print(sys.stdout.encoding, locale.getpreferredencoding() )
    endcoding = locale.getpreferredencoding()
    for line in sys.stdin:
        sys.stdout.buffer.write(line.encode(endcoding))
        sys.stdout.flush()
    """
    
            cmd = sys.executable, "-c", cmd
            # print(cmd, end="", flush=True)
            super().__init__(cmd, stdin=PIPE, bufsize=1, universal_newlines=True, creationflags=CREATE_NEW_CONSOLE, encoding='utf-8')
    
    
        def write(self, msg):
            self.stdin.write(msg + "\n" )
    
    if __name__ == "__main__":
        myConsole = console(color="c0", title="test error console")
        myConsole.write("Thank you jfs. Cool explanation")
        NoTitle= console()
        NoTitle.write("default color and title! This answer uses Windows 10")
        NoTitle.write(u"♥♥♥♥♥♥♥♥")
        NoTitle.write("♥")
        time.sleep(5)
        myConsole.terminate()
        NoTitle.write("some more text. Run this at the python console.")
        time.sleep(4)
        NoTitle.terminate()
        time.sleep(5)
    
    0 讨论(0)
  • 2020-11-29 06:06

    You can get something like two consoles using two Tkinter Text widgets.

    from Tkinter import *
    import threading
    
    class FakeConsole(Frame):
        def __init__(self, root, *args, **kargs):
            Frame.__init__(self, root, *args, **kargs)
    
            #white text on black background,
            #for extra versimilitude
            self.text = Text(self, bg="black", fg="white")
            self.text.pack()
    
            #list of things not yet printed
            self.printQueue = []
    
            #one thread will be adding to the print queue, 
            #and another will be iterating through it.
            #better make sure one doesn't interfere with the other.
            self.printQueueLock = threading.Lock()
    
            self.after(5, self.on_idle)
    
        #check for new messages every five milliseconds
        def on_idle(self):
            with self.printQueueLock:
                for msg in self.printQueue:
                    self.text.insert(END, msg)            
                    self.text.see(END)
                self.printQueue = []
            self.after(5, self.on_idle)
    
        #print msg to the console
        def show(self, msg, sep="\n"):
            with self.printQueueLock:
                self.printQueue.append(str(msg) + sep)
    
    #warning! Calling this more than once per program is a bad idea.
    #Tkinter throws a fit when two roots each have a mainloop in different threads.
    def makeConsoles(amount):
        root = Tk()
        consoles = [FakeConsole(root) for n in range(amount)]
        for c in consoles:
            c.pack()
        threading.Thread(target=root.mainloop).start()
        return consoles
    
    a,b = makeConsoles(2)
    
    a.show("This is Console 1")
    b.show("This is Console 2")
    
    a.show("I've got a lovely bunch of cocounts")
    a.show("Here they are standing in a row")
    
    b.show("Lorem ipsum dolor sit amet")
    b.show("consectetur adipisicing elit")
    

    Result:

    enter image description here

    0 讨论(0)
  • 2020-11-29 06:13

    Do you know about screen/tmux?

    How about tmuxp? For example, you can try to run cat in split panes and use "sendkeys" to send output (but dig the docs, may be there is even easier ways to achieve this).

    As a side bonus this will work in the text console or GUI.

    0 讨论(0)
提交回复
热议问题