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

Respuestas:

166

En lugar de barusar self.baro Foo.bar. Asignar a Foo.barcreará una variable estática y asignar a self.barcreará una variable de instancia.

Pavel Strakhov
fuente
12
Foo.bar funcionará, pero self.bar crea una variable de instancia, no estática.
bedwyr
47
bedwyr, "print self.bar" no creará ninguna variable de instancia (aunque la asignación a self.bar sí).
Constantin
@Constantin: no me di cuenta de eso, es una distinción interesante. Gracias por la corrección :-)
bedwyr
2
Pero si no tiene la intención de que haya un ivar, es más claro usar Foo.classmember.
mk12
2
Cuando se usan variables estáticas, es una buena idea leer los trucos desde aquí: stackoverflow.com/questions/68645/… . @Constantin ofrece una de las muchas trampas.
Trevor Boyd Smith
84

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
vartec
fuente
3
¿Por qué no solo Foo.bar, en lugar de self.__class__.bar?
mk12
15
@ Mk12: Cuando tienes herencia de clase, una "variable de clase" podría estar en una clase base o una subclase. ¿A qué quieres referirte? Depende de lo que intentes 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 la clase de la que sea un tipo de instancia.
Craig McQueen
77
Ahora hemos llegado a ese punto desafortunado cuando nos damos cuenta de los detalles del lenguaje que podemos discriminar entre dos casos de uso finamente sintonizados. De hecho, depende de lo que quieras hacer, pero muchas personas no atenderán esas sutilezas.
holdenweb
2
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 casi seguramente 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.
ToolmakerSteve
3
Estoy aprendiendo sobre cuándo usar variables y métodos de clase (a diferencia de las 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 a pesar de que bar es una variable de clase, no una variable de instancia.
Bill
13

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 mucha flexibilidad cuando se trata de variables de clase versus instancia. Lo mismo puede decirse de los métodos. Para obtener una buena lista de posibilidades, recomiendo leer la introducción de las clases de estilo nuevo de Michael Fötsch , especialmente las secciones 2 a 6.

Una cosa que requiere mucho trabajo para recordar al comenzar es que Python 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) son variables de instancia (o, si es estática, de clase) y son accesibles 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. Builtins

{begin pedagogy}

Hay excepciones limitadas a esto. Lo 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. Así:

>>> 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 no tiene acceso a ninguna de las variables que desea tener acceso, pero probablemente no de forma implícita. Si sus objetivos son simples y directos, entonces elegir Foo.bar o self.bar probablemente será suficiente. Si su ejemplo se está volviendo más complicado, o si desea hacer cosas elegantes 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í misma le parece incorrecta, consulte La introducción que he vinculado.

David Berger
fuente
IIRC, técnicamente se buscan 3 (+) espacios de nombres: función-local, módulo / global y componentes incorporados. Los ámbitos anidados significa que se pueden buscar múltiples ámbitos locales, pero ese es uno de los casos excepcionales. (...)
Jeff Shannon el
Además, tendría cuidado al decir 'módulo principal', ya que se busca el módulo que contiene la función, no el módulo principal ... Y buscar el atributo desde una referencia de instancia es algo diferente, pero esta respuesta explica por qué necesita la instancia / clase ref.
Jeff Shannon el
10
class Foo(object):
     bar = 1
     def bah(self):
         print Foo.bar

f = Foo() 
f.bah()
Allan Mwesigwa
fuente
-2
class Foo(object):    
    bar = 1

    def bah(object_reference):
        object_reference.var = Foo.bar
        return object_reference.var


f = Foo() 
print 'var=', f.bah()
Lopi Dani
fuente
44
Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación, y probablemente resultaría en más votos positivos. Recuerde que está respondiendo la pregunta para los lectores en el futuro, no solo la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos. De la opinión
doble pitido