10

First of all, I'd like to mention that I am not particularly familiar with Python. I have recently been forced to familiarise myself with a code sample that's left my jaws ajar, and I have been unable to "translate" it. The various documents and articles I've taken a look at have not helped either:

Here's a shortened-down version of the function in question:

@coroutine
def processMessage(receiver):
    global userID
    #...
    while True:
        msg = (yield)
        try:
            #...
        except Exception as err:
            #...

I cannot understand what it does and am thus not able to "walk through" the code. My questions are "What does this function do?" and "What sequences does this function follow?"

The line that throws me off is msg = (yield). I have no idea what it's trying to achieve. Intuition tells me it simply grabs new messages as they come through, but I fail to understand why. If anyone knows and if I have provided enough information, I'd really appreciate an explanation.

The Try clause:

if msg['event'] == 'message' and 'text' in msg and msg['peer'] is not None:
    if msg['sender']['username'] == username:
        userID = msg['receiver']['peer_id']
        config.read(fullpath + '/cfg/' + str(userID) + '.cfg')
        if config.has_section(str(userID)):
            log('Config found')
            readConfig()
            log('Config loaded')
        else:
            log('Config not found')
            writeConfig()
            log('New config created')
    if 'username' in msg['sender']:
        parse_text(msg['text'], msg['sender']['username'], msg['id'])

P.S. receiver is a socket receiver.

Pyromonk
  • 684
  • 1
  • 12
  • 27
  • What is it you wish to achieve? – johnashu Mar 03 '18 at 05:49
  • @johnashu, this is the only mention of `yield` in the file. It's a script that interacts with [telegram-cli](https://github.com/vysheng/tg). – Pyromonk Mar 03 '18 at 05:51
  • The function is described as a generator object, so the yield keyword is correct.. Can you add in the code for the try clause? I can guess that it will yield the msgs 1 at a time.. I cannot help but I am intrigued! – johnashu Mar 03 '18 at 05:56
  • 2
    `yield` totally works like that. This is a [coroutine](https://www.python.org/dev/peps/pep-0342/), in the old, pre-async sense. It's not clear what the question is trying to ask, though. – user2357112 Mar 03 '18 at 06:02
  • @johnashu, certainly, thank you! I have added the try clause code to my initial post. – Pyromonk Mar 03 '18 at 06:02
  • @johnashu What are you talking about? You can't name something yield, it would be syntax error – wim Mar 03 '18 at 06:05
  • What specific question are you trying to have answered here? – user2357112 Mar 03 '18 at 06:05
  • @user2357112, I'm just trying to walk through another person's code to understand what it's doing. I have previously consulted the `coroutine` entry, but I didn't realise it had anything to do with this syntax. I have updated my question to reflect this is indeed a `@coroutine` function. – Pyromonk Mar 03 '18 at 06:05
  • We can't answer this question without far more context and without the parts you deliberately removed, and even if you posted all that, the question would be too broad. Questions on Stack Overflow are supposed to be a lot more focused than this. – user2357112 Mar 03 '18 at 06:11
  • 2
    @user2357112, for a site that's supposed to facilitate learning and research it certainly fails. Without enough experience in the language I _can't_ present the problem properly. It's not _my_ code, so I can't present it in full. What am I supposed to do? Bang my head against the wall and curse everyone who downvotes and votes for closing the question? I've researched my question and I've tried to present it to the best of my ability. I apologise for not being perfect, but I'm just trying to learn. – Pyromonk Mar 03 '18 at 06:14

1 Answers1

24

The syntax variable = (yield some_value) in a generator does the following:

  • it returns some_value to the code that invoked it (via next or send);
  • when it is next invoked (via .next or .send(another_value)) it assigns another_value to variable and continues execution.

For example, suppose you have a generator function:

>>> def f():
...     while True:
...         given = (yield)
...         print("you sent me:", given)
...

Now, lets call f. That returns us a generator.

>>> g = f()

The very first time we use the generator we cannot send it data

>>> next(g)

At this point it just evaluated the yield ... when we now call .send it will continue from that point, assigning the data we have sent it to the variable given

>>> g.send("hello")
('you sent me:', 'hello')
>>> g.send("there")
('you sent me:', 'there')

In your particular sample code, you have a generator that is:

  • being given a message to process from outside ... something will be calling .send(some_msg);
  • it will be processing that message and then yielding back to the outside caller, which will then feed it another message.
donkopotamus
  • 22,114
  • 2
  • 48
  • 60
  • 2
    Thank you, kind sir! This is a very good illustration ot what's happening. I have not been able to find such a use case anywhere in the documentation. Thank you once more, it makes sense now. – Pyromonk Mar 03 '18 at 06:18