Python Language Les fonctions ignorent la portée de la classe lors de la recherche de noms


Exemple

Les classes ont une portée locale lors de la définition, mais les fonctions de la classe n'utilisent pas cette étendue lors de la recherche de noms. Comme les lambdas sont des fonctions et que les compréhensions sont implémentées à l'aide de la portée des fonctions, cela peut entraîner un comportement surprenant.

a = 'global'

class Fred:
    a = 'class'  # class scope
    b = (a for i in range(10))  # function scope
    c = [a for i in range(10)]  # function scope
    d = a  # class scope
    e = lambda: a  # function scope
    f = lambda a=a: a  # default argument uses class scope
    
    @staticmethod  # or @classmethod, or regular instance method
    def g():  # function scope
        return a

print(Fred.a)  # class
print(next(Fred.b))  # global
print(Fred.c[0])  # class in Python 2, global in Python 3
print(Fred.d)  # class
print(Fred.e())  # global
print(Fred.f())  # class
print(Fred.g()) # global

Les utilisateurs peu familiarisés avec le fonctionnement de cette étendue peuvent s'attendre à ce que b , c et e impriment la class .


De PEP 227 :

Les noms dans la portée de la classe ne sont pas accessibles. Les noms sont résolus dans la portée de la fonction la plus interne. Si une définition de classe se produit dans une chaîne de portées imbriquées, le processus de résolution ignore les définitions de classe.

De la documentation de Python sur la dénomination et la liaison :

La portée des noms définis dans un bloc de classe est limitée au bloc de classe; il ne s'étend pas aux blocs de code des méthodes - cela inclut les expressions de compréhension et de générateur car elles sont implémentées en utilisant une étendue de fonction. Cela signifie que les éléments suivants échoueront:

class A:
    a = 42
    b = list(a + i for i in range(10))

Cet exemple utilise les références de cette réponse de Martijn Pieters, qui contient une analyse plus approfondie de ce comportement.