Solution to Dummy Packet Assembler (Task from r/dailyprogrammer) I tried to solve the Packet Assembler task posted at r/dailyprogrammer.
The Question is this:

When a message is transmitted over the internet, it is split into multiple packets, each packet is transferred individually, and the packets are reassembled into the original message by the receiver. Because the internet exists in the real world, and because the real world can be messy, packets do not always arrive in the order in which they are sent. For today's challenge, your program must collect packets from stdin, assemble them in the correct order, and print the completed messages to stdout.
The point of reading from stdin is to simulate incoming packets. For the purposes of this challenge, assume there is a potentially unlimited number of packets. Your program should not depend on knowing how many packets there are in total. Simply sorting the input in its entirety would technically work, but defeats the purpose of this exercise.

Input Format is this:

Each line of input represents a single packet. Each line will be formatted as X Y Z some_text, where X Y and Z are positive integer and some_text is an arbitrary string. X represents the message ID (ie which message this packet is a part of). Y represents the packet ID (ie the index of this packet in the message) (packets are zero-indexed, so the first packet in a message will have Y=0, the last packet in a message will have Y=Z-1). Z represents the total number of packets in the message.

Here is the Python3 solution I did
from re import split

def add_id(packets, p_id, len):
    packets[p_id] = {}
    packets[p_id][&quot;len&quot;] = len
    packets[p_id][&quot;packets&quot;] = {}

    return packets


def add_packet(packets, p_id, p_num, p_len, msg):
    if p_id not in packets.keys():
        packets = add_id(packets, p_id, p_len)

    if p_num &gt; packets[p_id][&quot;len&quot;]:
        return packets

    packets[p_id][&quot;packets&quot;][p_num] = msg

    return packets


def main():
    packets = {}
    while True:
        try:
            recv = split(r'\s+', input())

            packets = add_packet(packets, int(recv[0]), int(recv[1]),
                                int(recv[2]), &quot; &quot;.join(recv[3:]))
        except EOFError:
            break

    for p_id in sorted(packets):
        for packet in range(packets[p_id][&quot;len&quot;]):
            print(&quot;%d %d %d %s&quot; %(p_id, packet, packets[p_id][&quot;len&quot;], packets[p_id][&quot;packets&quot;][packet]))


if __name__ == '__main__':
    main()

Please rate this solution and suggest some improvements that can be made?
I think this code is very straightforward and easy to read. Good job!

Some nitpicks are, 

You have a few PEP8 violations none all that concerning.


Should add a second white line between imports and your functions
Line too long, at your print statement
Continuation line under-indented for visual indent
printf style formatting is recommended against


Code suggestions

I would use a namedtuple instead of a dictionary, since it is much cleaner looking and easier to use. When to use a namedtuple!

Using the above suggestions and adhering PEP8 I get the following.

from re import split
from collections import namedtuple


def get_messages():
    Message = namedtuple('Message', 'idx num length message')
    messages = []

    while True:
        try:
            recv = split(r'\s+', input())
            messages.append(Message(recv[0], recv[1], recv[2], ' '.join(recv[3:])))
        except EOFError:
            return messages


def print_messages(messages):
    for message in messages:
        print("{}  {} {} {}"
            .format(message.idx, message.num, message.length, message.message))


def main():    
    messages = sorted(get_messages(), key=lambda x: (x.idx, x.num))
    print_messages(messages)


if __name__ == '__main__':
    main()