¿Es posible tener variables o métodos de clase estática en Python? ¿Qué sintaxis se requiere para hacer esto?
Las variables declaradas dentro de la definición de clase, pero no dentro de un método, son variables de clase o estáticas:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Como @ millerdev señala, esto crea una i
variable de nivel de clase , pero es distinta de cualquier i
variable de nivel de instancia , por lo que podría tener
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Esto es diferente de C ++ y Java, pero no tan diferente de C #, donde no se puede acceder a un miembro estático utilizando una referencia a una instancia.
Vea lo que el tutorial de Python tiene que decir sobre el tema de las clases y los objetos de clase .
@Steve Johnson ya ha respondido con respecto a los métodos estáticos , también documentados en "Funciones incorporadas" en la Referencia de la biblioteca de Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy recomienda classmethod s más métodoestático, como el método a continuación, recibe el tipo de clase como primer argumento, pero todavía estoy un poco borroso en las ventajas de este enfoque sobre métodoestático. Si tú también lo eres, entonces probablemente no importe.
@classmethod
sobre@staticmethod
AFAIK es que siempre obtienes el nombre de la clase en la que se invocó el método, incluso si se trata de una subclase. Un método estático carece de esta información, por lo que no puede llamar a un método anulado, por ejemplo.const.py
conPI = 3.14
y se puede importar en todas partes.from const import PI
i = 3
es una variable estática, es un atributo de clase, y dado que es distinto de un atributo de nivel de instancia , no se comporta como una variable estática en otros idiomas. Ver la respuesta de millerdev , la respuesta de Yann , y mi respuesta a continuación.i
i
(variable estática) estará en la memoria incluso si creo cientos de instancias de esta clase?@Blair Conrad dijo que las variables estáticas declaradas dentro de la definición de clase, pero no dentro de un método, son variables de clase o "estáticas":
Hay algunos gotcha's aquí. Continuando con el ejemplo anterior:
Observe cómo la variable de instancia
t.i
se desincronizó con la variable de clase "estática" cuando el atributoi
se configuró directamentet
. Esto se debe a quei
se volvió a vincular dentro delt
espacio de nombres, que es distinto delTest
espacio de nombres. Si desea cambiar el valor de una variable "estática", debe cambiarla dentro del alcance (u objeto) donde se definió originalmente. Puse "estática" entre comillas porque Python realmente no tiene variables estáticas en el sentido en que C ++ y Java sí.Aunque no dice nada específico sobre variables o métodos estáticos, el tutorial de Python tiene información relevante sobre clases y objetos de clase .
@Steve Johnson también respondió con respecto a los métodos estáticos, también documentados en "Funciones incorporadas" en la Referencia de la biblioteca de Python.
@beid también mencionó classmethod, que es similar a staticmethod. El primer argumento de un método de clase es el objeto de clase. Ejemplo:
fuente
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Ahora usted puede hacerx = Test()
,x.i = 12
,assert x.i == Test.i
.Métodos estáticos y de clase
Como han señalado las otras respuestas, los métodos estáticos y de clase se logran fácilmente utilizando los decoradores integrados:
Como de costumbre, el primer argumento de
MyMethod()
está vinculado al objeto de instancia de clase. Por el contrario, el primer argumento deMyClassMethod()
está vinculado al objeto de clase en sí (por ejemplo, en este casoTest
). PorqueMyStaticMethod()
ninguno de los argumentos está vinculado, y tener argumentos es opcional."Variables estáticas"
Sin embargo, implementar "variables estáticas" (bueno, variables estáticas mutables , de todos modos, si eso no es una contradicción en términos ...) no es tan sencillo. Como señaló millerdev en su respuesta , el problema es que los atributos de clase de Python no son realmente "variables estáticas". Considerar:
Esto se debe a que la línea
x.i = 12
ha agregado un nuevo atributo de instanciai
enx
lugar de cambiar el valor del atributo deTest
clasei
.El comportamiento parcial esperado de la variable estática, es decir, la sincronización del atributo entre varias instancias (pero no con la clase en sí misma; consulte "gotcha" a continuación), puede lograrse convirtiendo el atributo de clase en una propiedad:
Ahora puedes hacer:
La variable estática ahora permanecerá sincronizada entre todas las instancias de clase .
(NOTA: Es decir, a menos que una instancia de clase decida definir su propia versión de
_i
! Pero si alguien decide hacer ESO, se merece lo que obtiene, ¿no?)Tenga en cuenta que técnicamente hablando,
i
todavía no es una "variable estática" en absoluto; es unproperty
, que es un tipo especial de descriptor. Sin embargo, elproperty
comportamiento ahora es equivalente a una variable estática (mutable) sincronizada en todas las instancias de clase."Variables estáticas" inmutables
Para el comportamiento inmutable de la variable estática, simplemente omita el
property
setter:Ahora, intentar establecer el
i
atributo de instancia devolverá unAttributeError
:Uno tiene que ser consciente de
Tenga en cuenta que los métodos anteriores solo funcionan con instancias de su clase; no funcionarán cuando se use la clase en sí . Así por ejemplo:
La línea
assert Test.i == x.i
produce un error, porque eli
atributo deTest
yx
son dos objetos diferentes.Mucha gente encontrará esto sorprendente. Sin embargo, no debería ser. Si volvemos e inspeccionamos nuestra
Test
definición de clase (la segunda versión), tomamos nota de esta línea:Claramente, el miembro
i
deTest
debe ser unproperty
objeto, que es el tipo de objeto devuelto por laproperty
función.Si encuentra lo anterior confuso, lo más probable es que todavía lo esté pensando desde la perspectiva de otros lenguajes (por ejemplo, Java o c ++). Debe estudiar el
property
objeto, el orden en que se devuelven los atributos de Python, el protocolo descriptor y el orden de resolución del método (MRO).Presento una solución para el 'gotcha' anterior a continuación; sin embargo, sugeriría, enérgicamente, que no intente hacer algo como lo siguiente hasta que, como mínimo, comprenda completamente por qué
assert Test.i = x.i
causa un error.Variables estáticas REALES, REALES -
Test.i == x.i
Presento la solución (Python 3) a continuación solo con fines informativos. No lo estoy respaldando como una "buena solución". Tengo mis dudas sobre si emular el comportamiento variable estático de otros lenguajes en Python es realmente necesario. Sin embargo, independientemente de si es realmente útil, lo siguiente debería ayudar a comprender mejor cómo funciona Python.
ACTUALIZACIÓN: este intento es realmente horrible ; si insiste en hacer algo como esto (pista: por favor, no lo haga; Python es un lenguaje muy elegante y no es necesario que se comporte como otro idioma), use el código en la respuesta de Ethan Furman .
Emulación del comportamiento de variables estáticas de otros idiomas usando una metaclase
Una metaclase es la clase de una clase. La metaclase predeterminada para todas las clases en Python (es decir, las clases de "nuevo estilo" posteriores a Python 2.3, creo) es
type
. Por ejemplo:Sin embargo, puede definir su propia metaclase de esta manera:
Y aplíquelo a su propia clase de esta manera (solo Python 3):
A continuación se muestra una metaclase que he creado que intenta emular el comportamiento de "variable estática" de otros idiomas. Básicamente funciona reemplazando el getter, setter y deleter predeterminados con versiones que verifican si el atributo solicitado es una "variable estática".
Un catálogo de las "variables estáticas" se almacena en el
StaticVarMeta.statics
atributo. Todas las solicitudes de atributos se intentan resolver inicialmente mediante un orden de resolución sustituto. Lo he denominado el "orden de resolución estática" o "SRO". Esto se hace buscando el atributo solicitado en el conjunto de "variables estáticas" para una clase dada (o sus clases principales). Si el atributo no aparece en el "SRO", la clase recurrirá al comportamiento predeterminado get / set / delete del atributo (es decir, "MRO").fuente
Test
(antes de usarlo para crear instancias) como perteneciente al dominio de la metaprogramación? Por ejemplo, altera el comportamiento de clase haciendoTest.i = 0
(aquí simplemente destruye el objeto de propiedad por completo). Supongo que el "mecanismo de propiedad" solo se aplica al acceso a la propiedad en instancias de una clase (a menos que cambie el comportamiento subyacente utilizando una metaclase como intermediario, tal vez). Por cierto, por favor termine esta respuesta :-)También puede agregar variables de clase a clases sobre la marcha
Y las instancias de clase pueden cambiar las variables de clase
fuente
Personalmente, usaría un método de clase siempre que necesitara un método estático. Principalmente porque obtengo la clase como argumento.
o usa un decorador
Para propiedades estáticas ... Es hora de buscar alguna definición de Python ... la variable siempre puede cambiar. Hay dos tipos de ellos mutables e inmutables. Además, hay atributos de clase y atributos de instancia. Nada como atributos estáticos en el sentido de java & c ++
¡Por qué usar el método estático en sentido pitónico, si no tiene relación alguna con la clase! Si fuera usted, usaría classmethod o definiría el método independientemente de la clase.
fuente
Una cosa especial a tener en cuenta sobre las propiedades estáticas y las propiedades de instancia, que se muestra en el siguiente ejemplo:
Esto significa que antes de asignar el valor a la propiedad de instancia, si intentamos acceder a la propiedad a través de la instancia, se utiliza el valor estático. Cada propiedad declarada en la clase python siempre tiene una ranura estática en la memoria .
fuente
Los métodos estáticos en python se denominan classmethod s. Echa un vistazo al siguiente código
Tenga en cuenta que cuando llamamos al método myInstanceMethod , obtenemos un error. Esto se debe a que requiere que se llame al método en una instancia de esta clase. El método myStaticMethod se establece como un método de clase utilizando el decorador @classmethod .
Solo por patadas y risitas, podríamos llamar a myInstanceMethod en la clase pasando una instancia de la clase, así:
fuente
@staticmethod
;@classmethod
es (obviamente) para métodos de clase (que están destinados principalmente para su uso como constructores alternativos, pero pueden servir en un apuro como métodos estáticos que reciben una referencia a la clase por la que fueron llamados).Cuando se define alguna variable miembro fuera de cualquier método miembro, la variable puede ser estática o no estática dependiendo de cómo se exprese la variable.
Por ejemplo:
Los resultados son
fuente
Es posible tener
static
variables de clase, pero probablemente no valga la pena.Aquí hay una prueba de concepto escrita en Python 3: si alguno de los detalles exactos es incorrecto, el código se puede ajustar para que coincida con lo que quiera decir con
static variable
:y en uso:
y algunas pruebas:
fuente
También podría exigir que una clase sea estática usando metaclase.
Luego, cuando accidentalmente intentes inicializar MyClass , obtendrás un StaticClassError.
fuente
__new__
sus padres ...Un punto muy interesante sobre la búsqueda de atributos de Python es que se puede usar para crear " variables virtuales ":
Normalmente no hay asignaciones a estos después de que se crean. Tenga en cuenta que la búsqueda se usa
self
porque, aunquelabel
es estático en el sentido de que no está asociado con una instancia en particular , el valor aún depende de la (clase de) instancia.fuente
Con respecto a esta respuesta , para una variable estática constante , puede usar un descriptor. Aquí hay un ejemplo:
Resultando en ...
Siempre puede plantear una excepción si ignorar silenciosamente el valor de configuración (
pass
arriba) no es lo suyo. Si está buscando una variable de clase estática de estilo C ++, Java:Eche un vistazo a esta respuesta y al CÓMO oficial de documentos para obtener más información sobre los descriptores.
fuente
@property
, que es lo mismo que usar un descriptor, pero es mucho menos código.Absolutamente sí, Python por sí solo no tiene ningún miembro de datos estáticos explícitamente, pero podemos tenerlo al hacerlo
salida
explicación
fuente
Sí, definitivamente es posible escribir variables y métodos estáticos en python.
Variables estáticas: las variables declaradas a nivel de clase se denominan variables estáticas a las que se puede acceder directamente utilizando el nombre de la clase.
Variables de instancia: las variables relacionadas y a las que se accede por instancia de una clase son variables de instancia.
Métodos Estáticos: similar a las variables, se puede acceder directamente a los métodos estáticos utilizando el nombre de clase. No es necesario crear una instancia.
Pero tenga en cuenta que un método estático no puede llamar a un método no estático en python.
fuente
Para evitar cualquier posible confusión, me gustaría contrastar variables estáticas y objetos inmutables.
Algunos tipos de objetos primitivos como enteros, flotantes, cadenas y touples son inmutables en Python. Esto significa que el objeto al que se refiere un nombre dado no puede cambiar si es de uno de los tipos de objeto mencionados anteriormente. El nombre se puede reasignar a un objeto diferente, pero el objeto en sí no se puede cambiar.
Hacer que una variable estática lleve esto un paso más allá al no permitir que el nombre de la variable apunte a cualquier objeto que no sea el que apunta actualmente. (Nota: este es un concepto de software general y no específico de Python; consulte las publicaciones de otros para obtener información sobre la implementación de estadísticas en Python).
fuente
La mejor manera que encontré es usar otra clase. Puede crear un objeto y luego usarlo en otros objetos.
Con el ejemplo anterior, hice una clase llamada
staticFlag
.Esta clase debe presentar la var estática
__success
(Private Static Var).tryIt
La clase representa la clase regular que necesitamos usar.Ahora hice un objeto para una bandera (
staticFlag
). Esta bandera se enviará como referencia a todos los objetos regulares.Todos estos objetos se están agregando a la lista
tryArr
.Resultados de esta secuencia de comandos:
fuente
Variables estáticas en clase de fábrica python3.6
Para cualquiera que use una fábrica de clases con python3.6 y superior, use la
nonlocal
palabra clave para agregarla al alcance / contexto de la clase que se está creando así:fuente
hasattr(SomeClass, 'x')
esFalse
. dudo que esto sea lo que alguien quiere decir con una variable estática en absoluto.some_var
inmutable y estáticamente definido, o no? ¿Qué tiene que ver el acceso externo al getter con una variable que es estática o no? Tengo tantas preguntas ahora. Me encantaría escuchar algunas respuestas cuando tenga tiempo.some_var
arriba no es un miembro de la clase en absoluto. En Python se puede acceder a todos los miembros de la clase desde fuera de la clase.nonlocal
keywoard "golpea" el alcance de la variable. El alcance de una definición de cuerpo de clase es independiente del alcance en el que se encuentra cuando usted dicenonlocal some_var
, eso es solo crear una referencia de nombre no local (leer: NO en el alcance de definición de clase) a otro objeto con nombre. Por lo tanto, no se adjunta a la definición de clase porque no está en el ámbito del cuerpo de la clase.Entonces esto es probablemente un truco, pero he estado usando
eval(str)
para obtener un objeto estático, una especie de contradicción, en Python 3.Hay un archivo Records.py que no tiene más que
class
objetos definidos con métodos estáticos y constructores que guardan algunos argumentos. Luego, desde otro archivo .py,import Records
pero necesito seleccionar dinámicamente cada objeto y luego instanciarlo a pedido de acuerdo con el tipo de datos que se están leyendo.Entonces, ¿dónde
object_name = 'RecordOne'
o el nombre de la clase? Llamocur_type = eval(object_name)
y luego para instanciarlo.cur_inst = cur_type(args)
Sin embargo, antes de crear una instancia, puede llamar a métodos estáticos,cur_type.getName()
por ejemplo, como una implementación de clase base abstracta o cualquier objetivo. Sin embargo, en el back-end, probablemente se instancia en Python y no es realmente estático, porque eval está devolviendo un objeto ... que debe haber sido instanciado ... que da un comportamiento estático.fuente
Puede usar una lista o un diccionario para obtener un "comportamiento estático" entre las instancias.
fuente
Si está intentando compartir una variable estática para, por ejemplo, aumentarla en otras instancias, algo como este script funciona bien:
fuente