Devo rinominare le variabili che sono già costanti nella mia libreria?

3

Sto scrivendo un wrapper di alto livello sull'oggetto Python socket.socket . Nello specifico, voglio farlo per i socket TCP IPv4 (anche se sarebbe utile poter espandere la libreria in un secondo momento con altre famiglie / tipi). Come forse saprai, il modulo socket definisce questi come socket.AF_INET e socket.SOCK_STREAM . È una buona idea "copiare" queste costanti e renderle costanti attributi di classe, cioè:

import socket


class IPv4TCPSocket(socket):
    FAMILY = socket.AF_INET
    TYPE = socket.SOCK_STREAM

    def __init__(self):
        ...

O dovrei fare riferimento a loro direttamente? Questa potrebbe sembrare una domanda strana visto che sono già costanti nel modulo socket , ma riferirsi ad esse con <libname>.socket.AF_INET potrebbe essere un po 'imbarazzante. Qualche idea su questo?

In alternativa, non esco dagli attributi della classe e inizializzo in questo modo:

super().__init__(family=socket.AF_INET, type=socket.SOCK_STREAM)

Questo lascia completamente un riferimento alla famiglia e al tipo di socket, che non è un problema, a meno che qualcun altro debba creare un socket personalizzato (o derivarne uno da IPv4TCPSocket ):

from <name> import IPv4TCPSocket as sock


print("Creating a new socket with family {} and type {}!".format(sock.FAMILY, sock.TYPE))

Contrariamente a

import <libname>

print("Creating a new socket with family {} and type {}!".format(<libname>.socket.AF_INET, <libname>.socket.SOCK_STREAM))

È un po 'più di lavoro e non mi sembra un'interfaccia pubblica intuitiva per me. E hey, potrei semplicemente trasformarlo in un problema più grande di quanto sia in realtà, ma lo faccio molto:)

Seconda modifica: nuove idee sull'argomento. Dopo aver letto il commento di James, ho scoperto (ancora, duh!) Che socket.socket.type e socket.socket.family esistono, che restituiscono rispettivamente il tipo e la famiglia dell'istanza socket. Quindi, dal momento che voglio separare il comportamento di classe su un tipo & base familiare, non posso affatto sottoclasse socket . La domanda rimane la stessa, tuttavia, poiché ciascuna di queste istanze wrapper richiede anche un attributo privato di _socket di ordinamento.

L'unico vero motivo che posso trovare è quello di rendere l'interfaccia pubblica più facile da usare. O potrei anche lasciare gli attributi del tutto dal momento che il nome della classe descrive il socket. Decisioni, decisioni.

Le risposte sono ancora benvenute, ma ho deciso di rimuovere le costanti e lasciare che il nome della classe significhi la sua famiglia e il tipo.

    
posta Daniel 05.12.2017 - 20:31
fonte

1 risposta

3

Risposta generica alla domanda:

La vera domanda di progettazione è se si vuole perdere o mostrare le dipendenze sottostanti della libreria. A meno che tu non abbia davvero delle buone ragioni per farlo, è meglio non esporre i "materiali di costruzione" interni del tuo software sulle sue API. L'ignoranza è beatitudine qui.

La prima e più importante ragione è che se "nascondi" ciò che stai usando, la tua biblioteca non è sposata con quella dipendenza finché la morte non le distrugge. Se un giorno hai trovato un'altra libreria che serve meglio ai tuoi scopi (o decidi di implementare tu stesso quella funzionalità), puoi fare lo scambio senza che i tuoi utenti se ne accorgano.

E poi, un'altra ragione è che la maggior parte delle volte i tuoi utenti cercano un'astrazione / semplificazione sulle librerie di basso livello non elaborate. Vogliono soluzioni "non farmi pensare" con API minimaliste ed eleganti che permettano loro di fare merda in fretta e senza sprecare cicli cerebrali extra. Se esponi o perdi dettagli interni sulla tua API, stai solo facendo in modo che i tuoi utenti debbano conoscere i dettagli non necessari e rendere la loro vita più difficile senza una buona ragione.

Detto questo, ci sono situazioni in cui potresti voler "sposarti" e avere una sorta di "API leaky" invece di un'astrazione completa. Ad esempio se fornisci funzionalità extra in una determinata sottoclasse e desideri che i tuoi utenti utilizzino la tua nuova classe come sostituta drop-in.

Risposta concreta al tuo problema:

Se stai progettando una classe chiamata IPv4TCPSocket , non ha alcun senso rendere family o type in alcun modo visibile o configurabile, dal momento che un socket TCP definisce piuttosto una determinata famiglia e tipo. Fare così confonderebbe gli utenti e renderebbe l'astrazione un po 'assurda. L'approccio più pulito sarebbe quello di memorizzare l'istanza socket sottostante nei membri privati della classe ed esporre i membri desiderati.

    
risposta data 11.12.2017 - 23:05
fonte

Leggi altre domande sui tag