Cela marche:
from typing import Tuple NUM_DIMENSIONS = 2 # Might change at a later point in time # Should be equivalent to Tuple[float ,float] Result = Tuple[*([float] * NUM_DIMENSIONS)] def get() -> Result: ...
mais ce n'est pas le cas:
import numpy as np def lookup(a: np.ndarray, coordinates: tuple) -> float: return a[*coordinates] a1 = np.zeros((2, 2)) print(lookup(a1, (0, 1)) # Should print 0 a2 = np.zeros(2, 2, 2)) print(lookup(a2, (0, 0, 1)) # Should print 0
Comment décompresser les tuples lors de l'indexation?
Voici deux exemples où j'aimerais utiliser cette approche, mais je suis plus intéressé à comprendre pourquoi *
-unpacking ne semble pas être pris en charge dans l'indexation en général.
x = ['foo', 'bar'] y[*x] # raises SyntaxError (not NameError!)
ou
x = ['foo', 'bar'] y = [*x] print(y) # prints ['foo', 'bar']
3 Réponses :
En vous référant à votre exemple:
>> a[[1, 1, 0], [0]] array([[4, 5], [4, 5], [0, 1]])
NumPy accepte déjà l'indexation comme a[coordinates]
où les coordinates
sont un tuple, sans avoir besoin de l'opérateur étoile:
>>> a = np.arange(8).reshape(2, 2, 2) >>> a[(1, 1, 0)] 6
Et si vous indexez avec des listes, vous obtenez un autre type de comportement utile:
import numpy as np def lookup(a: np.ndarray, coordinates: tuple) -> float: return a[*coordinates] a1 = np.zeros((2, 2)) print(lookup(a1, (0, 1)) a2 = np.zeros(2, 2, 2)) print(lookup(a2, (0, 0, 1))
Merci pour votre participation. Comme je l'ai écrit, je suis moins soucieux de faire fonctionner les exemples et plus de comprendre pourquoi mon approche ne fonctionne pas (même si je serais intéressé par une solution de contournement pour mon exemple de typing
).
L'indexation de Python a déjà un support intégré pour les tuples en général (pas seulement pour NumPy), il n'est donc pas nécessaire de décompresser ici.
En général, foo[x]
est le sucre syntaxique pour le type(foo).__getitem__(foo, x)
. Voyons comment cela fonctionne en détail:
x = 1, 2 print(repr(x)) # prints (1, 2)
Si nous indexons dans foo
avec une seule valeur, alors il est passé à __getitem__
inchangé, qu'il s'agisse d'un scalaire, d'une liste ou d'un tuple:
foo[0, 1] # prints (0, 1)
Le cas intéressant est ce qui se passe lorsque nous fournissons plusieurs valeurs directement lors de l'indexation (sans les envelopper dans un tuple ou une liste):
foo[0] # prints 0 foo[(0, 1)] # prints (0, 1) foo[[0, 1]] # prints [0, 1]
Ainsi, plusieurs valeurs sont automatiquement enveloppées dans un tuple! foo
ne peut pas faire la distinction entre foo[0, 1]
et foo[(0, 1)]
. En effet, dans la grammaire Python , l'index est une expression (ou une tranche, mais cela ne s'applique pas ici) - et dans une expression, a ,
forme un tuple:
class Foo: def __getitem__(self, key): print(repr(key)) foo = Foo()
Par conséquent, l'analyse des arguments dans l'indexation fonctionne différemment des appels de fonction (où les virgules séparent les arguments au lieu de former des tuples).
Donc, dans l'ensemble, il n'est pas nécessaire de décompresser l'itérateur lors de l'indexation. Convertissez simplement votre itérateur en tuple et utilisez-le comme index.
>>> x = ['foo', 'bar'] >>> print(*x) foo bar >>> print(x) ['foo', 'bar'] >>> y[*x] File "<stdin>", line 1 y[*x] ^ SyntaxError: invalid syntax >>> y[foo bar] #this is y[*x] File "<stdin>", line 1 y[foo bar] ^ SyntaxError: invalid syntax
Votre erreur pour le type(*x)
est que x
a le mauvais nombre d'éléments. La décompression de l'itérateur dans les arguments de fonction fonctionne bien pour type
: type(*[1])
renvoie int
. La première partie de votre deuxième exemple est ce que je demande (et vous ne donnez aucune explication ici), et il manque une virgule dans la deuxième partie de votre deuxième exemple.
type (* ['foo', 'bar']) ou type (* [1,2]) vous donnerait l'erreur que j'ai spécifiée. De plus, il n'y a pas de virgule manquante, mais le * x lui-même affiche foo bar plutôt que ['foo', 'bar'] à moins que je ne vous ai mal compris.
Oui, type(*['foo', 'bar'])
donnerait également la même erreur, mais je ne vois pas ce que cela a à voir avec la syntaxe de décompression de tuple qui n'est pas prise en charge dans les opérations d'indexation. Comme je l'ai dit, le déballage est bien pris en charge dans les appels de fonction. Concernant la virgule manquante: je ne vois pas en quoi y[foo bar]
est censé être une syntaxe Python valide et ce que cela a à voir avec le déballage - votre commentaire this is y[*x]
n'a pas beaucoup de sens, car y[*x]
n'est pas défini (c'est le sujet de ma question) et s'il était défini, il ne serait sûrement pas étendu à quelque chose de syntaxiquement invalide comme y[foo bar]
.
y = [* x], je me suis référé à votre question et y [* x] vous donne l'erreur de syntaxe (comme pour la question), donc mon point d'explication était que y [* x] vous donnera une erreur de syntaxe et vous obtenez cela parce qu'accéder à y [* x] accède à y [foo bar] qui est syntaxiquement incorrecte comme prévu.
Je ne pense pas que " y[*x]
accède à y[foo bar]
" ait un sens. Que signifie "accéder"? Comme vous pouvez le voir dans ma réponse, il s'agit de savoir comment exactement y[x]
désucre en type(y).__getitem__(y, x)
et sur quel type d'entité grammaticale est attendue entre [
et ]
(par exemple, une expression vs. une liste de paramètres).
Dans votre deuxième extrait,
y
n'a pas été introduit comme variable, doncy[*x]
ne signifie rien, d'où l'erreur de syntaxe.Comment pensez-vous que l'indexation fonctionne avec
['foo', 'bar']
ici? L'indexation nécessite un entier individuel, pas une liste de chaînesPouvez-vous montrer un exemple avec les sorties souhaitées pour les entrées?
@quamrana: Non, une déclaration de variable manquante déclenche une
NameError
, pas uneSyntaxError
. Essayeznot_declared[0]
.@Chris_Rands: pour les listes qui peuvent être vraies. Mais les tableaux NumPy, les Pandas DataFrames et
typing
génériques detyping
ont une interface d'indexation beaucoup plus compliquée et supportent des choses commefoo[a, b, c]
. Voir mes exemples.@Chris_Rands J'ai mis à jour mes exemples avec le comportement attendu