2009-06-19 7 views
4

J'ai une fonction de classe qui doit « passer à travers » un argument de mot clé:arguments de mot-clé Passthrough

def createOrOpenTable(self, tableName, schema, asType=Table): 
    if self.tableExists(tableName): 
     return self.openTable(tableName, asType=asType) 
    else: 
     return self.createTable(self, tableName, schema, asType=asType) 

Quand je l'appelle, je reçois une erreur comme ceci:

TypeError: createTable() got multiple values for keyword argument 'asType' 

Existe-t-il un moyen de "passer à travers" un tel argument mot-clé?

J'ai pensé à plusieurs réponses, mais aucune d'elles n'est optimale. De pire au meilleur:

  • je pouvais changer le nom du mot clé sur un ou plusieurs des fonctions, mais je veux utiliser le même mot-clé pour les trois fonctions, car le paramètre a le même sens.

  • je pourrais passer le paramètre asType par la position plutôt que par mot-clé, mais si j'ajouter d'autres paramètres de mots clés à openTable ou createTable, je dois vous rappeler de changer les appels. Je préfère l'adapter automatiquement, comme si je pouvais utiliser le mot-clé. Je pourrais utiliser le formulaire **args à la place, pour obtenir un dictionnaire de paramètres de mot-clé plutôt que d'utiliser un paramètre par défaut, mais cela semble être l'utilisation d'un sledgehammer pour écraser une mouche (à cause des lignes de code supplémentaires nécessaires pour bien analyse-le).

Y a-t-il une meilleure solution?

Répondre

9

Vous faites bien ... Il suffit de prendre le self dans la deuxième fonction appel :)

return self.createTable(self, tableName, schema, asType=asType) 

devrait être:

return self.createTable(tableName, schema, asType=asType) 
+0

D'oh Comme! –

+0

Même si Python est, dans l'ensemble, assez sympa quand vous les frappez pour la première fois. L'autre que vous frapperez si vous n'avez pas encore défini une méthode sans argument 'self' ... Votre programme mourra avec une erreur incroyablement utile "nombre incorrect d'arguments". –

+0

Oui, je l'ai frappé très tôt. Heureusement, j'ai vite compris. –

5

Je dois dire que je suis pensé à un problème plus compliqué. Mais la réponse de David Wolever est absolument correcte. C'est juste le moi dupliqué ici, qui crée le problème. De cette façon, les paramètres positionnels sont décalés et asType reçoit une valeur en tant que paramètre possible (une fois) et en tant que paramètre-clé (deuxième fois!).

Un problème beaucoup plus intéressant est, que faire, lorsque vous souhaitez améliorer la routine appelée (createTable dans l'exemple) sans améliorer à chaque fois la fonction intermédiaire. Ici, la solution args ** fait l'affaire:

Par exemple:

def createOrOpenTable(self, tableName, schema, **args): 
    if self.tableExists(tableName): 
     return self.openTable(tableName, **args) 
    else: 
     return self.createTable(tableName, schema, **args) 

De cette manière, il est possible d'améliorer la signature de createTable et OpenTable sans avoir à changer createOrOpenTable plus.

Quand créer et OpenTable peut avoir des mots clés paramètres, doivent être définis bien sûr les deux routines comme suit:

def createTable(self, tableName, schema, asType=None, **others): 
    ... 

Le paramètre autres dévore tous les paramètres de mots clés inconnus à la méthode - il est également pas nécessaire de l'évaluer.

+1

est 'def def' une faute de frappe? – Geoff

+0

@Geoff: Oui c'est le cas. – Juergen

5

J'aurais posté un commentaire à la publication de Juergen, mais j'ai besoin d'écrire un exemple de code. Voici un peu la version plus générique: «pass-through »

def createOrOpenTable(self, tableName, schema, *args, **argd): 
    if self.tableExists(tableName): 
     return self.openTable(tableName, *args, **argd) 
    else: 
     return self.createTable(tableName, schema, *args, **argd) 

Cela permettra des arguments de position d'être aussi efficace (ce qui est important si vous voulez vraiment que ce soit un

+0

Salut Jason, merci pour la solution plus générique! Je n'y ai pas pensé, car dans ma pratique, il ne s'est encore produit que des paramètres optionnels supplémentaires (qui sont en fait des paramètres de mots-clés) - pas de paramètres possibles. Bien sûr, il est possible d'avoir des paramètres supplémentaires, mais la plupart du temps, votre interface principale sera corrigée - et seuls les paramètres optionnels apparaîtront dans le futur. – Juergen

+0

C'est vrai. Je faisais juste remarquer cela par souci d'exhaustivité. :-) –

+1

est 'def def' une faute de frappe? – Geoff