Comment convertir un délégué VB en gestionnaire d'événements python?

Nov 16 2020

Je dois réécrire le code VB suivant qui s'abonne à un délégué (événement), en python, en utilisant python.net .

Imports MtApi

Public Class Form1
    Private apiClient As MtApiClient

    Public Sub New()
        InitializeComponent()
        apiClient = New MtApiClient
        AddHandler apiClient.QuoteUpdated, AddressOf QuoteUpdatedHandler
    End Sub

    Sub QuoteUpdatedHandler(sender As Object, symbol As String, bid As Double, ask As Double)
        Dim quoteSrt As String
        quoteSrt = symbol + ": Bid = " + bid.ToString() + "; Ask = " + ask.ToString()
        ListBoxQuotesUpdate.Invoke(Sub()
                                       ListBoxQuotesUpdate.Items.Add(quoteSrt)
                                   End Sub)
        Console.WriteLine(quoteSrt)
    End Sub

    ' These can be ignored for this discussion
    Private Sub btnConnect_Click(sender As System.Object, e As System.EventArgs) Handles btnConnect.Click
        apiClient.BeginConnect(8222)
    End Sub

    Private Sub btnDisconnect_Click(sender As System.Object, e As System.EventArgs) Handles btnDisconnect.Click
        apiClient.BeginDisconnect()
    End Sub
End Class

Ce code VB fait partie d'une application VB pour le pont mtapi .NET.

Q: Quelle est la bonne façon de convertir ce délégué VB en un gestionnaire d'événements python?


J'ai déjà essayé de nombreuses variantes de ce qui suit:

...
import MtApi as mt
...
# apiClient_QuoteUpdated(object sender, string symbol, double bid, double ask)
def printTick(symbol, ask, bid):
    print('Tick: Symbol: {}  Ask: {:.5f}  Bid: {:.5f}'.format(symbol, ask, bid))


class OnTick:
    def __init__(self):
        self.listeners = []

    def __iadd__(self, listener):
        # Shortcut for using += to add a listener
        self.listeners.append(listener)
        return self

    def notify(self, *args, **kwargs):
        for listener in self.listeners:
            listener(*args, **kwargs)

mtc = mt.MtApiClient()
res = mtc.BeginConnect('127.0.0.1', 8222);

# This Works!
newTick = OnTick()
newTick += printTick
newTick.notify(SYM, 1.12400, 1.12300)

# This does NOT work!
newTick.notify(mtc.QuoteUpdate())
# TypeError: 'EventBinding' object is not callable

J'ai regardé les réponses ici:

  • Quelle est la bonne façon de convertir cette inscription de gestionnaire d'événements de C # à VB.net?
  • Les classes Python prennent-elles en charge les événements comme les autres langages?

Réponses

not2qubit Nov 24 2020 at 05:19

Comme étroitement lié à cette réponse dans une question similaire, le problème était de trop compliquer le code des délégués. Nous n'avons tout simplement pas besoin de la classe OnTick et nous sommes également conscients que le QuoteUpdatedHandler()besoin de 4 arguments , nous le remplaçons printTick(...)par cela.

(Bien sûr, si vous voulez faire quelque chose d'un peu plus compliqué ou élégant , vous voulez le créer dans une classe.)

Ensuite, le code Python équivalent à pour le délégué VB, devient:

...
def QuoteUpdatedHandler(source, sym, bid, ask) :
    qstr = '{}: {:.5f} {:.5f}'.format(sym,bid,ask)
    print(qstr)

...
mtc = mt.MtApiClient()

print('Connecting...')
res = mtc.BeginConnect('127.0.0.1', 8222);

# VB: AddHandler mtc.QuoteUpdated, AddressOf QuoteUpdatedHandler
# Because we want the "AddressOf" of the function, we don't use the invoking "()"
mtc.QuoteUpdated += QuoteUpdatedHandler

print('ok')

# Now run in a loop and wait for the events:
while 1:
    pass
    try: 
        time.sleep(0.1)
    except KeyboardInterrupt:
        print('\n  Break!')
        break

if (mtc.IsConnected()) :
    mtc.PlaySound("tick")
    mtc.BeginDisconnect()
print('\n  Done!')

sys.exit(2)