SimPy - init - positional argument missing

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
hcshm
User
Beiträge: 48
Registriert: Dienstag 11. Februar 2020, 08:23

Mir wird in nachfolgendem Script folgender Fehler angezeigt:
TypeError: __init__() missing 1 required positional argument: 'item'
Leider stehe ich mit meinen Kenntnissen noch ziemlich am Anfang und bitte um Unterstützung.

""" Abbildung eines einfachen Kommunikationsprozesses
sender sourct eine Message aus einem store (Gehirn)
gibt sie über einen msgcarrier an den receiver weiter
receiver legt die message in seinem store (Gehirn) ab"""

import simpy

SIM_DURATION = 5

class Msgcarrier(object):
"""Klasse für Träger von messages"""
def __init__(self, env):
self.env = env
self.source = simpy.Store(env)
self.store = simpy.Store(env)

def get(self):
return self.source.get()

def put(self):
return self.store.put()

def sender(env, msgcarrier):
"""Abruf von messages aus source"""
while True:
msgget = yield msgcarrier.get()
print('Message aus Source entnommen und weitergeleitet um {}'.format(env.now))

def receiver(env, msgcarrier):
"""Empfang und Ablage im store"""
while True:
msgput = yield msgcarrier.put()
print('Message empfangen und im Store abegelegt um {}'.format(env.now))
yield env.timeout(1)

env = simpy.Environment()

msgcarrier = Msgcarrier(env)
env.process(sender(env, msgcarrier))
env.process(receiver(env, msgcarrier))

env.run(until=SIM_DURATION)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Es wäre es nur gut, zu wissen, wo genau der Fehler auftritt. Denn das verrät Dir, wo Du schauen mußt, was falsch ist.
Man könnte auch den gesunden Menschenverstand einsetzen: wenn ich irgendwo etwas hineintun will, dann brauche ich auch irgend ein ETWAS.
hcshm
User
Beiträge: 48
Registriert: Dienstag 11. Februar 2020, 08:23

Vielen Dank, der Fehler weist zurück auf die Zeilen
msgput = yield msgcarrier.put()
msgget = yield msgcarrier.get()
Ich kann den Hinweis auf das ETWAS verstehen, komme aber trotzdem nicht weiter
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Was Du da mit `put` dem Store hinzufügen willst, weiß ich auch nicht. Das sollte doch aus dem Problem, das Du lösen möchtest, klar sein.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@hcshm: Das „denglisch“ im Modul-Docstring ist ja fürchterlich. Kannst Du Dich da nicht entweder für Deutsch *oder* für Englisch entscheiden?

Namen sollten keine kryptischen Abkürzungen enthalten. `Msgcarrier` sollte beispielsweise `MessageCarrier` heissen.

Das ETWAS sollten doch wohl *Nachrichten* sein. `msgget` sollte also `message` heissen und `msgput` macht keinen Sinn denn nur das `get()` liefert ja eine Nachricht, während das `put()` eine Nachricht in den `Store` tut — was denkst Du denn was von der Aktion der Rückgabewert sein sollte? Da fehlt aber halt die Nachricht. Du musst da irgendetwas in den Store rein tun. Wie so eine Nachricht aussieht ist letztlich Dir überlassen. Vielleicht eine Zeichenkette "Nachricht", wobei man die dann vielleicht auch nummerieren sollte die Nachrichten, damit man sie auseinanderhalten kann!?

Und man muss `MessageCarrier.put()` natürlich auch die Nachricht übergeben.

Das der `sender()` eine Nachricht mit `get()` ermittelt ist komisch. Das ist ja eher empfangen als senden. Was auch nicht funktionieren wird ist auch einem `Store` in den niemals etwas rein getan wird, etwas heraus zu holen. Wo sollen diese Objekte denn her kommen? Ein `Store` ist erst einmal *leer* wenn man ihn erstellt.

Der `receiver()` tut dagegen Nachrichten in den/einen `Store` was eher senden als empfangen ist.

Zwischenstand der allerdings nicht funktioniert weil `sender()` ewig blockiert weil der `Store` niemals etwas enthalten wird/kann.

Code: Alles auswählen

#!/usr/bin/env python3
"""
:todo: Deutsch *oder* Englisch!

Abbildung eines einfachen Kommunikationsprozesses sender sourct eine Message aus
einem store (Gehirn) gibt sie über einen carrier an den receiver weiter
receiver legt die message in seinem store (Gehirn) ab
"""
from itertools import count

import simpy

SIM_DURATION = 5


class MessageCarrier:
    """Klasse für Träger von messages"""

    def __init__(self, env):
        self.source = simpy.Store(env)
        self.store = simpy.Store(env)

    def get(self):
        return self.source.get()

    def put(self, message):
        return self.store.put(message)


def sender(env, carrier):
    """
    Abruf von messages aus source
    """
    while True:
        #
        # TODO Etwas sinnvolles mit `message` machen.
        #
        message = yield carrier.get()
        print(f"Message aus Source entnommen und weitergeleitet um {env.now}")


def receiver(env, carrier):
    """
    Empfang und Ablage im store
    """
    for i in count(1):
        yield carrier.put(f"Nachricht {i}")
        print(f"Message empfangen und im Store abegelegt um {env.now}")
        yield env.timeout(1)


def main():
    env = simpy.Environment()

    carrier = MessageCarrier(env)
    env.process(sender(env, carrier))
    env.process(receiver(env, carrier))

    env.run(until=SIM_DURATION)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was irgendwie auch nicht zu der Beschreibung im Docstring passt sind die beiden `Store`\s beim `MessageCarrier`. Bei den beiden `Store`\s die in der Beschreibung erwähnt werden steht dahinter in Klammern „Gehirn“. Damit ist doch sicher das jeweilige Gehirn von Sender und Empfänger gemeint, und da ist es doch komisch das die ihr Gehirn gar nicht selbst haben sondern beide ihr Gehirn beim Nachrichtenträger, also extern und im gleichen Objekt haben.

Soll der Nachrichtenträger denn überhaupt als Klasse modelliert werden? Und nicht vielleicht als weiterer Prozess oder überhaupt nicht, denn man könnte da ja einfach noch einen `Store` als Kommunikationskanal zwischen Sender und Empfänger verwenden. Man kann das ja beliebig (unnötig) kompliziert machen. Ich finde die `Store`\s für die Gehirne ja schon irgendwie überflüssig weil das keinen Einfluss auf die Simulation hat. Die würde ohne letztlich genau so ablaufen. Oder man könnte einfach Listen dafür nehmen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Also die einfachste Variante mit einem `Store` als FIFO:

Code: Alles auswählen

#!/usr/bin/env python3
from itertools import count

import simpy

SIM_DURATION = 5


def receiver(env, channel):
    while True:
        print(f"Empfänger empfängt {yield channel.get()} @ {env.now}")


def sender(env, channel):
    for i in count(1):
        message = f"Nachricht {i}"
        print(f"Sender sendet {message} @ {env.now}")
        yield channel.put(message)
        yield env.timeout(1)


def main():
    env = simpy.Environment()

    channel = simpy.Store(env)
    env.process(sender(env, channel))
    env.process(receiver(env, channel))

    env.run(until=SIM_DURATION)


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

Sender sendet Nachricht 1 @ 0
Empfänger empfängt Nachricht 1 @ 0
Sender sendet Nachricht 2 @ 1
Empfänger empfängt Nachricht 2 @ 1
Sender sendet Nachricht 3 @ 2
Empfänger empfängt Nachricht 3 @ 2
Sender sendet Nachricht 4 @ 3
Empfänger empfängt Nachricht 4 @ 3
Sender sendet Nachricht 5 @ 4
Empfänger empfängt Nachricht 5 @ 4
Nachrichtenübertragung dauert hier 0 Zeiteinheiten. Wenn man das verändern will, könnte man noch einen Prozess schreiben der die Übertragungszeit regelt und zwischen Sender um Empfänger steht:

Code: Alles auswählen

#!/usr/bin/env python3
from itertools import count

import simpy

SIM_DURATION = 5


def receiver(env, channel):
    while True:
        print(f"Empfänger empfängt {yield channel.get()!r} @ {env.now}")


def sender(env, channel):
    for i in count(1):
        message = f"Nachricht {i}"
        print(f"Sender sendet {message!r} @ {env.now}")
        yield channel.put(message)
        yield env.timeout(1)


def carrier(env, in_channel, out_channel):
    while True:
        message = yield in_channel.get()
        print(f"Nachricht {message!r} auf dem Weg @ {env.now}")
        yield env.timeout(1)
        yield out_channel.put(message)
        print(f"Nachricht {message!r} übertragen @ {env.now}")


def main():
    env = simpy.Environment()

    sending_end = simpy.Store(env)
    env.process(sender(env, sending_end))
    receiving_end = simpy.Store(env)
    env.process(receiver(env, receiving_end))
    env.process(carrier(env, sending_end, receiving_end))

    env.run(until=SIM_DURATION)


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

Sender sendet 'Nachricht 1' @ 0
Nachricht 'Nachricht 1' auf dem Weg @ 0
Sender sendet 'Nachricht 2' @ 1
Nachricht 'Nachricht 1' übertragen @ 1
Empfänger empfängt 'Nachricht 1' @ 1
Nachricht 'Nachricht 2' auf dem Weg @ 1
Sender sendet 'Nachricht 3' @ 2
Nachricht 'Nachricht 2' übertragen @ 2
Empfänger empfängt 'Nachricht 2' @ 2
Nachricht 'Nachricht 3' auf dem Weg @ 2
Sender sendet 'Nachricht 4' @ 3
Nachricht 'Nachricht 3' übertragen @ 3
Empfänger empfängt 'Nachricht 3' @ 3
Nachricht 'Nachricht 4' auf dem Weg @ 3
Sender sendet 'Nachricht 5' @ 4
Nachricht 'Nachricht 4' übertragen @ 4
Empfänger empfängt 'Nachricht 4' @ 4
Nachricht 'Nachricht 5' auf dem Weg @ 4
Wie man sieht geht hier jetzt die 5. Nachricht auf den Weg, kommt aber innerhalb der `SIM_DURATION` nicht mehr an weil die Übertragung nun auch eine Zeiteinheit beansprucht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten