print("sending { to { }formatdataself socket getpeername()[ ])self socket send(datadef close(self)self socket close(this class decorates socket object and presents the send and close interface to client sockets better decorator would also implement (and possibly customizeall of the remaining socket methods it should properly implement all of the arguments to send(which actually accepts an optional flags argumentas wellbut let' keep our example simplewhenever send is called on this objectit logs the output to the screen before sending data to the client using the original socket we only have to change one line in our original code to use this decorator instead of calling respond with the socketwe call it with decorated socketrespond(logsocket(client)while that' quite simplewe have to ask ourselves why we didn' just extend the socket class and override the send method we could call super(send to do the actual sendingafter we logged it there is nothing wrong with this design either when faced with choice between decorators and inheritancewe should only use decorators if we need to modify the object dynamicallyaccording to some condition for examplewe may only want to enable the logging decorator if the server is currently in debugging mode decorators also beat multiple inheritance when we have more than one optional behavior as an examplewe can write second decorator that compresses data using gzip compression whenever send is calledimport gzip from io import bytesio class gzipsocketdef __init__(selfsocket)self socket socket def send(selfdata)buf bytesio(zipfile gzip gzipfile(fileobj=bufmode=" "zipfile write(datazipfile close(self socket send(buf getvalue()def close(self)self socket close(