broadcast(channels, msg) that calls .send(msg) on every object in channels and collects the results — plus two example channels, Email returning f'email: {msg}' and Sms returning f'sms: {msg}'. No shared base class, no isinstance: if it has send, it is a channel. That is duck typing.broadcast([Email(), Sms()], 'hi')
['email: hi', 'sms: hi']
Each object answered the same message its own way.
A list comprehension over channels.
The interface is implicit — just the method name.