2017-06-14 2 views
3

Nach help(getattr), zwei oder drei Argumente werden akzeptiert:Ist es möglich, eine Funktionssignatur zu schreiben, die sich wie getattr() verhält?

getattr(...) 
    getattr(object, name[, default]) -> value 

einige einfache Tests tun, können wir dies bestätigen:

>>> obj = {} 
>>> getattr(obj, 'get') 
<built-in method get of dict object at 0x7f6d4beaf168> 
>>> getattr(obj, 'bad', 'with default') 
'with default' 

Zu wenige/zu viele Argumente auch wie erwartet verhalten:

Die im Hilfetext angegebenen Argumentnamen scheinen nicht als Schlüsselwortargumente akzeptiert zu werden:

>>> getattr(object=obj, name='get') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: getattr() takes no keyword arguments 

Das inspect Modul ist keine Hilfe hier:

>>> import inspect 
>>> inspect.getargspec(getattr) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/inspect.py", line 816, in getargspec 
    raise TypeError('{!r} is not a Python function'.format(func)) 
TypeError: <built-in function getattr> is not a Python function 

(messaging is a little different in python3, but the gist is the same) 

Nun ist die Frage: Gibt es eine einfache Möglichkeit, meine eigene Python-Funktion mit einer Signatur zu schreiben, die genau wie getattr ‚Unterschrift verhält? Das heißt, Schlüsselwortargumente sind nicht erlaubt und minimale/maximale Anzahl von Argumenten wird erzwungen. Die nächstgelegene ich gekommen, ist die folgende:

def myfunc(*args): 
    len_args = len(args) 
    if len_args < 2: 
     raise TypeError('expected at least 2 arguments, got %d' % len_args) 
    elif len_args > 3: 
     raise TypeError('expected at most 3 arguments, got %d' % len_args) 
    ... 

Aber jetzt statt sinnvollen Argumente Namen wie object und name wir bekommen args[0] und args[1]. Es ist auch eine Menge Standard, und fühlt sich geradezu unangenehm an. Ich weiß, dass eine eingebaute, getattr sehr unterschiedliche Implementierung als typischer Python-Code haben muss, und vielleicht gibt es keine Möglichkeit, die Art, wie es sich verhält, perfekt zu emulieren. Aber es ist eine Kuriosität, die ich seit einer Weile habe.

+0

@Makoto: kein Duplikat; optionale Argumente sind einfach, aber diese Frage sucht auch nur nach positionsbezogenen Argumenten. – user2357112

Antwort

3

Diese Art von Funktionssignaturen sind speziell für in C geschriebene Funktionen mit der C-Level-Funktionsfamilie PyArg_Parse* und dem Argument Clinic Preprozessor. Es gibt keine integrierte Möglichkeit, diese Art von Signatur in Python zu schreiben. Der nächste, den Sie bekommen können, ist, was Sie bereits herausgefunden haben, mit *args.

(Nebenbei gibt ist bereits Syntax für den Fall ausgesucht sie entscheiden tun, um diese Funktionalität zu implementieren, in PEP 457 beschrieben, aber jetzt ist die Syntax nur in der Dokumentation verwendet werden, und eine leichte Variante ist in der Argumentationsklinik verwendet.)

+0

Aber es kann normalerweise getan werden. – martineau

+0

@martineau: So weit ich weiß, ist es am nächsten, wenn man '* args' manuell parsen kann, was der Fragesteller bereits herausgefunden hat. – user2357112

+0

Ja, aber die Art, wie sie es tun, ist vielleicht nicht die einfachste. Für das spezielle Beispiel in ihrer Frage scheint mir ein einfaches 'def myfunc (obj, name, default = None):' würde ausreichen - obwohl sie die 'None' durch irgendeine Art von einzigartigem Wert ersetzen müssten, wenn dies der Fall wäre ein zulässiger Argumentwert Dies ist auch einfach zu tun ... – martineau

3

Dieser Code tickt die meisten Ihrer Anforderungen:

def anonymise_args(fn): 
    @functools.wraps(fn) 
    def wrap(*args): 
     return fn(*args) 
    return wrap 


@anonymise_args 
def myfunc(obj, name, default=None): 
    print obj, name, default 
  • Stichwort Argumente

    x.myfunc(obj=1, name=2) 
    TypeError: wrap() got an unexpected keyword argument 'obj' 
    
  • A minumum/maximale Anzahl der Argumente durchgesetzt werden

    x.myfunc(1,2,3,4) 
    TypeError: myfunc() takes at most 3 arguments (4 given) 
    
  • sind nicht erlaubt
  • aussagekräftigen Argument Namen

  • nicht viel vorformulierten

+0

Haben Sie 'functools.wraps' in Ihren Tests weggelassen? Die erste Fehlermeldung sieht nicht richtig aus. – user2357112

+0

Außerdem sollten Sie in 'wrap' wahrscheinlich 'zurückgeben', um Rückgabewerte korrekt zu übergeben, wenn Funktionen mit sinnvollen Rückgabewerten umschlossen werden. – user2357112

+0

1) Ich habe 'functools.wraps' in meine Tests aufgenommen. Ich weiß nicht, warum die Fehlermeldung 'wrap()' enthält. 2) Ja, 'wrap' sollte' return' enthalten. –

Verwandte Themen