2016-06-14 20 views
8

stavo scrivendo un codice che trova "metodi Unbound" di una classe utilizzando l'introspezione e sono rimasto sorpreso di vedere due diversi tipi di descrittori per i tipi built-:Differenza tra descrittori "wrapper" e "metodo"?

>>> type(list.append), list.append 
(<class 'method_descriptor'>, <method 'append' of 'list' objects>) 
>>> type(list.__add__), list.__add__ 
(<class 'wrapper_descriptor'>, <slot wrapper '__add__' of 'list' objects>) 

Searching the docs alzato molto limitato, ma interessanti risultati:

  1. A note in the inspect module che inspect.getattr_static non risolve i descrittori e include un codice che può essere utilizzato per risolverli.
  2. an optimization made in python 2.4 sostenendo che method_descriptor è più efficiente di wrapper_descriptor ma non spiegando quello che sono:

    I metodi list.__getitem__(), dict.__getitem__(), e dict.__contains__() sono ora implementato come method_descriptor oggetti piuttosto che wrapper_descriptor oggetti. Questa forma di accesso raddoppia le loro prestazioni e le rende più adatte all'utilizzo come argomenti per i funzionali: map(mydict.__getitem__, keylist).

La differenza di prestazioni del tutto mi ha incuriosito, chiaramente v'è una differenza così sono andato alla ricerca di ulteriori informazioni.

Nessuno di questi tipi sono nel modulo types:

>>> import types 
>>> type(list.append) in vars(types).values() 
False 
>>> type(list.__add__) in vars(types).values() 
False 

utilizzando help non fornisce tutte le informazioni utili:

>>> help(type(list.append)) 
Help on class method_descriptor in module builtins: 

class method_descriptor(object) 
| Methods defined here: 
| 
    <generic descriptions for> 
     __call__, __get__, __getattribute__, __reduce__, and __repr__ 
| 
| ---------------------------------------------------------------------- 
| Data descriptors defined here: 
| 
| __objclass__ 
| 
| __text_signature__ 

>>> help(type(list.__add__)) 
Help on class wrapper_descriptor in module builtins: 

class wrapper_descriptor(object) 
| Methods defined here: 
| 
    <generic descriptions for> 
     __call__, __get__, __getattribute__, __reduce__, and __repr__ 
| 
| ---------------------------------------------------------------------- 
| Data descriptors defined here: 
| 
| __objclass__ 
| 
| __text_signature__ 

Searching the internet solo si avvicinò con risultati su "che cosa è un descrittore "o riferimenti vaghi ai tipi specifici coinvolti.

Quindi la mia domanda è:

Qual è la differenza reale tra <class 'method_descriptor'> e <class 'wrapper_descriptor'>?

+1

Non fidatevi di 'inspect' per quanto riguarda i descrittori. Vedi https://bugs.python.org/issue26103 (anche rilevante: http://stackoverflow.com/q/3798835/541136) –

+0

@AaronHall Ho pensato di includerne uno ma non l'altro era probabilmente una svista ma non ero sicuro , Tornerò alla versione che non ha evidenziato l'incoerenza dei documenti di ispezione. –

risposta

1

È un dettaglio di implementazione. A livello C, un tipo predefinito come list definisce metodi come append per nome attraverso una matrice di strutture PyMethodDef, mentre metodi speciali come __add__ vengono definiti in modo più indiretto.

__add__ corrisponde ad un puntatore a funzione in uno dei due slot sq_concat nella del tp_as_sequence o nb_add tipo nel tipo di tp_as_number. Se un tipo definisce uno di questi slot, Python genera uno wrapper_descriptor avvolgendo quello slot per il metodo __add__ dell'API Python.

L'involucro necessario per le finestre di tipo e le strutture PyMethodDef è leggermente diverso; ad esempio, due slot potrebbero corrispondere a un metodo o uno slot potrebbe corrispondere a sei metodi.Gli slot inoltre non portano con sé i loro nomi dei metodi, mentre il nome del metodo è uno dei campi in uno PyMethodDef. Poiché per i due casi è necessario un codice diverso, Python utilizza diversi tipi di wrapper per racchiuderli.

Se volete vedere il codice, sia method_descriptor e wrapper_descriptor sono implementati in Objects/descrobject.c, con typedef struct in Include/descrobject.h. È possibile visualizzare il codice che inizializza i wrapper in Objects/typeobject.c, dove PyType_Ready delegati a add_operators per wrapper_descriptor s e add_methods per method_descriptor s.

+0

La maggior parte sembra corretta, ma cosa intendi per "anche le slot non portano con sé i loro nomi di metodo"? Posso ancora fare 'list .__ add __.__ name__' e tornare' '__add __' ' –

+0

@ TadhgMcDonald-Jensen: lo slot 'sq_concat' a livello C ha solo un puntatore a funzione. Lo slot wrapper deve contenere il nome '__add__'. – user2357112

+0

Potresti aggiungere collegamenti al codice sorgente che supportano queste informazioni? La differenza essendo un dettaglio di implementazione è sicuramente la risposta corretta poiché Jython non ha un 'wrapper_descriptor' ma non ho ancora riferimenti che descrivano come funziona una delle due classi. –

0

Sembra che method_descriptor e wrapper_descriptor siano una sorta di callables disponibili in CPython. La differenza tra loro sembra essere semplice method_descriptor è apparentemente usato per i metodi di incasso (implementato in C) oggetti:

set.__dict__['union'].__class__ 
<class 'wrapper_descriptor'> 

wrapper_descriptor viene utilizzato ad esempio i gestori di tipi predefiniti:

This is the place dove ho trovato questa informazione.

+0

Capisco cosa 'method_wrapper' è, è il costruito in equivoco a' 'che viene usato per i metodi associati, sto chiedendo la differenza tra' method_descriptor' e 'wrapper_descriptor'. –

Problemi correlati