¿Cómo puedo acceder a las variables de clase “estáticas” dentro de los métodos?

8 minutos de lectura

Avatar de usuario de Ross Rogers
ross rogers

Si tengo el siguiente código:

class Foo(object):
    bar = 1

    def bah(self):
        print(bar)
        
f = Foo()
f.bah()

se queja

NameError: el nombre global ‘bar’ no está definido

¿Cómo puedo acceder a la clase/variable estática? bar dentro del método bah?

  • Puede encontrar más información sobre Python y la estática aquí: stackoverflow.com/questions/68645/python-static-variable

    – camawyr

    1 de abril de 2009 a las 21:57

En vez de bar usar self.bar o Foo.bar. Asignando a Foo.bar creará una variable estática, y asignando a self.bar creará una variable de instancia.

  • Foo.bar funcionará, pero self.bar crea una variable de instancia, no una estática.

    – camawyr

    1 de abril de 2009 a las 21:55

  • bedwyr, “print self.bar” no creará ninguna variable de instancia (aunque la asignación a self.bar sí lo hará).

    – Constantino

    1 de abril de 2009 a las 22:14

  • @Constantin: no me di cuenta de eso, es una distinción interesante. Gracias por la corrección 🙂

    – camawyr

    3 de abril de 2009 a las 1:14

  • Pero si no tiene la intención de que haya un ivar, es más claro usar Foo.classmember.

    – mk12

    13 de septiembre de 2009 a las 20:58

  • cuando se usan variables estáticas, es una buena idea leer las trampas desde aquí: stackoverflow.com/questions/68645/… . @Constantin da una de las muchas trampas.

    – Trevor Boyd Smith

    21 de marzo de 2017 a las 16:27


avatar de usuario de vartec
vartec

Definir método de clase:

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

Ahora si bah() tiene que ser un método de instancia (es decir, tener acceso a uno mismo), aún puede acceder directamente a la variable de clase.

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

  • ¿Por qué no solo Foo.bar, en lugar de self.__class__.bar?

    – mk12

    13 de septiembre de 2009 a las 20:59

  • @Mk12: cuando tiene herencia de clase, una “variable de clase” podría estar en una clase base o una subclase. ¿A cuál quieres referirte? Depende de lo que estés tratando de hacer. Foo.bar siempre se referiría a un atributo de la clase especificada, que podría ser una clase base o una subclase. self.__class__.bar se referiría a cualquier clase de la que sea tipo la instancia.

    –Craig McQueen

    11 de diciembre de 2009 a las 4:47

  • Ahora hemos llegado a ese desafortunado punto en el que somos tan conscientes de los detalles del lenguaje que podemos discriminar entre dos casos de uso finamente armonizados. De hecho, depende de lo que quieras hacer, pero muchas personas no prestarán atención a tales sutilezas.

    – holdenweb

    14 de diciembre de 2011 a las 10:19

  • Por cierto, este es un uso RARO de “variable de clase”. Mucho más común tenerlo definido en una clase específica, aquí Foo. Esta es información útil para algunas situaciones de programación avanzada. Pero es casi seguro que no es lo que la pregunta original quería como respuesta (cualquiera que necesite ESTA respuesta ya sabrá cómo hacer Foo.bar). +1 porque aprendí algo de esto.

    – El fabricante de herramientas Steve

    25 de noviembre de 2013 a las 17:05


  • Estoy aprendiendo sobre cuándo usar variables y métodos de clase (a diferencia de variables y métodos de instancia). Cuando desea acceder a una variable de clase en un método de instancia, ¿es necesario usar self.__class__.bar? Noté que self.bar funciona aunque bar es una variable de clase, no una variable de instancia.

    – Factura

    29/03/2015 a las 18:30

Avatar de usuario de David Berger
david berger

Como con todos los buenos ejemplos, ha simplificado lo que realmente está tratando de hacer. Esto es bueno, pero vale la pena señalar que python tiene un lote de flexibilidad cuando se trata de variables de clase versus instancia. Lo mismo puede decirse de los métodos. Para una buena lista de posibilidades, recomiendo leer Introducción a las clases de nuevo estilo de Michael Fötschespecialmente las secciones 2 a 6.

Una cosa que cuesta mucho trabajo recordar al empezar es que pitón no es java. Más que un simple cliché. En java, se compila una clase completa, lo que hace que la resolución del espacio de nombres sea realmente simple: cualquier variable declarada fuera de un método (en cualquier lugar) es una variable de instancia (o, si es estática, de clase) y es accesible implícitamente dentro de los métodos.

Con python, la gran regla general es que hay tres espacios de nombres que se buscan, en orden, para las variables:

  1. La función/método
  2. El módulo actual
  3. Construidos

{begin pedagogy}

Hay excepciones limitadas a esto. El principal que se me ocurre es que, cuando se carga una definición de clase, la definición de clase es su propio espacio de nombres implícito. Pero esto dura solo mientras se carga el módulo, y se omite por completo cuando se encuentra dentro de un método. De este modo:

>>> class A(object):
        foo = 'foo'
        bar = foo


>>> A.foo
'foo'
>>> A.bar
'foo'

pero:

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

Al final, lo que hay que recordar es que usted hacer tener acceso a cualquiera de las variables a las que desea acceder, pero probablemente no implícitamente. Si sus objetivos son simples y directos, probablemente sea suficiente optar por Foo.bar o self.bar. Si su ejemplo se está volviendo más complicado, o quiere hacer cosas sofisticadas como la herencia (¡puede heredar métodos estáticos/de clase!), o la idea de referirse al nombre de su clase dentro de la clase en sí le parece incorrecta, consulte la introducción que vinculé.

  • IIRC, técnicamente se han buscado 3 (+) espacios de nombres: función local, módulo/global e incorporados. Ámbitos anidados significa que se pueden buscar varios ámbitos locales, pero ese es uno de los casos excepcionales. (…)

    –Jeff Shannon

    2 de abril de 2009 a las 8:52

  • Además, tendría cuidado al decir ‘módulo principal’, ya que es el módulo que contiene la función el que se busca, no el principal módulo… Y buscar el atributo de una referencia de instancia es algo diferente, pero esta respuesta explica por qué necesita la referencia de instancia/clase.

    –Jeff Shannon

    2 de abril de 2009 a las 8:57

Avatar de usuario de Allan Mwesigwa
Allan Mwesigwa

class Foo(object):
     bar = 1
     def bah(self):
         print Foo.bar

f = Foo() 
f.bah()

Avatar de usuario de Parik Chudasma
Parik Chudasma

bar es su variable estática y puede acceder a ella usando Foo.bar.

Básicamente, debe calificar su variable estática con el nombre de clase.

  • Considere agregar más información para ampliar su respuesta, o considere editar otras respuestas para agregar este detalle.

    – Usuario1010

    5 de enero de 2021 a las 18:59

Puedes acceder variables de clase por objeto y directamente por nombre de la clase desde el exterior o el interior de la clase y, básicamente, debe acceder variables de clase directamente por nombre de la clase porque si hay la misma clase de nombre y variables de instancia, variable de instancia del mismo nombre se prioriza mientras variable de instancia del mismo nombre se ignora cuando se accede por objeto. Entonces, usando nombre de la clase es más seguro que usar objeto acceder variables de clase.

Por ejemplo, puede acceder a la variable de clase por objeto y directamente por nombre de clase desde fuera de la clase, como se muestra a continuación:

class Person:
    name = "John" # Class variable

obj = Person()
print(obj.name) # By object
print(Person.name) # By class name

Producción:

John
John

Pero, si agrega la misma variable de instancia de nombre que la variable de clase por objeto:

class Person:
    name = "John" # Class variable

obj = Person()
obj.name = "Tom" # Adds the same name instance variable as class variable
print(obj.name) # By object
print(Person.name) # By class name

O, si agrega la misma variable de instancia de nombre que la variable de clase por self en __init__():

class Person:
    name = "John" # Class variable
    
    def __init__(self, name):
        self.name = name # Adds the same name instance variable as class variable

obj = Person("Tom")
print(obj.name) # By object
print(Person.name) # By class name

La misma variable de instancia de nombre tiene prioridad cuando se accede por objeto:

Tom  # By object
John # By class name

Y, también puede acceder a la variable de clase por self y directamente por nombre de clase desde el interior del método de instancia como se muestra a continuación:

class Person:
    name = "John" # Class variable
        
    def test(self): # Instance method
        print(self.name) # By "self"
        print(Person.name) # By class name

obj = Person()
obj.test()

Producción:

John
John

Pero, si agrega la misma variable de instancia de nombre que la variable de clase por objeto:

class Person:
    name = "John" # Class variable
        
    def test(self): # Instance method
        print(self.name) # By "self"
        print(Person.name) # By class name

obj = Person()
obj.name = "Tom" # Adds the same name instance variable as the class variable
obj.test()

O, si agrega la misma variable de instancia de nombre que la variable de clase por self en __init__():

class Person:
    name = "John" # Class variable
    
    def __init__(self, name):
        self.name = name # Adds the same name instance variable as the class variable
        
    def test(self): # Instance method
        print(self.name) # By "self"
        print(Person.name) # Directly by class name

obj = Person("Tom")
obj.test()

La misma variable de instancia de nombre tiene prioridad cuando se accede a ella self:

Tom  # By "self"
John # By class name

  • Considere agregar más información para ampliar su respuesta, o considere editar otras respuestas para agregar este detalle.

    – Usuario1010

    5 de enero de 2021 a las 18:59

¿Ha sido útil esta solución?