Teifión
¿Hay alguna diferencia entre estas clases además del nombre?
class WithClass ():
def __init__(self):
self.value = "Bob"
def my_func(self):
print(self.value)
class WithoutClass ():
value = "Bob"
def my_func(self):
print(self.value)
¿Hay alguna diferencia si uso o no uso el __init__
método para declarar la variable value
?
Mi principal preocupación es que lo usaré de una manera, cuando eso me cause más problemas en el futuro.
S. Lott
Conjunto de variables fuera __init__
pertenecen a la clase. Son compartidos por todas las instancias.
Variables creadas dentro __init__
(y todas las demás funciones del método) y precedida de self.
pertenecen a la instancia del objeto.
-
Eso no es lo que Python hace por mí. Las listas/dictados/etc se comparten entre todas las instancias si no las crea en
__init__()
.– demasiado php
8 de octubre de 2009 a las 11:43
-
@demasiado php: todas las variables en el método de clase (independientemente de la mutabilidad, las listas y los dictados son mutables) se comparten. Con objetos inmutables, compartir no es interesante. Con objetos mutables (listas y dictados), el intercambio es significativo.
– S. Lott
8 de octubre de 2009 a las 11:58
-
Sospeché que ese podría ser el caso, pero pensé que si declaraba mis suposiciones, podría distraer la atención de la pregunta en sí, aplausos por aclararla 🙂
– Teifión
8 de octubre de 2009 a las 18:54
-
Pensé que esto era lo que estaba sucediendo, pero no estaba muy claro para mí. Gracias por aclararme.
– dimo414
22 de febrero de 2011 a las 10:49
-
Esto es un poco engañoso. A
varname
conjunto de variables fuera del en eso pertenece a la clase, y se puede leer a través deself.varname
produciendo el mismo valor para todas las instancias. Sin embargo, cuando se le asigna un valor a través de una referencia de instancia (como enself.varname = X
) a nuevo Se creará self.varname solo para esa instancia, oscureciendo la variable de clase. La clase var permanece accesible a través de una referencia de clase (por ejemplo:WithClass.varname
). Y las variables de clase también se pueden configurar desde cualquier método al comenzar con el nombre de la clase (WithClass.myvar = X
) en lugar de una referencia de instancia (self.myvar = X
).– Lobotomik
8 de marzo de 2017 a las 11:26
sin uno mismo
Crea algunos objetos:
class foo(object):
x = 'original class'
c1, c2 = foo(), foo()
Puedo cambiar la instancia c1 y no afectará a la instancia c2:
c1.x = 'changed instance'
c2.x
>>> 'original class'
Pero si cambio la clase foo, todas las instancias de esa clase también cambiarán:
foo.x = 'changed class'
c2.x
>>> 'changed class'
Tenga en cuenta cómo funciona el alcance de Python aquí:
c1.x
>>> 'changed instance'
Con uno mismo
Cambiar la clase no afecta a las instancias:
class foo(object):
def __init__(self):
self.x = 'original self'
c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
-
tenga en cuenta que este ejemplo funciona solo para clases de tipo nuevas, con las antiguas, tendrán el mismo resultado
– Abdelouahab
4 de enero de 2015 a las 0:57
-
@Abdelouahab, ¿es así? Lo probé con clases de estilo antiguo y obtuve el mismo resultado que los objetos de estilo nuevo. Pitón 2.7.8
– farmear
6 de agosto de 2015 a las 1:01
alejandro
Me gustaría agregar algo a las respuestas que leí en este hilo y este hilo (que hace referencia a este).
Descargo de responsabilidad: estos comentarios provienen de los experimentos que realicé
Variables fuera __init__
:
Estos son, de hecho, variables de clase estáticas y son, por tanto, accesibles a todas las instancias de la clase.
Variables dentro __init__
:
El valor de estos variables de instancia sólo son accesibles a la instancia en cuestión (a través del self
referencia)
Mi contribución:
Una cosa que los programadores deben tener en cuenta al usar variables de clase estáticas es que pueden ser sombreados por variables de instancia (si está accediendo a la variables de clase estáticas a través de self
referencia).
Explicación:
Anteriormente, pensaba que ambas formas de declarar las variables eran exactamente iguales (tonto de mí), y eso se debía en parte a que podía acceder a ambos tipos de variables a través del self
referencia. Fue ahora, cuando me encontré con problemas, que investigué el tema y lo aclaré.
El problema de acceder variables de clase estáticas a través de
self
referencia es que solo hace referencia a la variable de clase estática si no hay Instancia variable con el mismo nombre, y para colmo, intentando redefinir un variable de clase estática a través de self
referencia no funciona porque un Instancia variable se crea que luego sombrea el previamente accesible variable de clase estática.
Para evitar este problema, siempre debe hacer referencia a variables de clase estáticas a través del nombre de la clase.
Ejemplo:
#!/usr/bin/env python
class Foo:
static_var="every instance has access"
def __init__(self,name):
self.instance_var="I am %s" % name
def printAll(self):
print 'self.instance_var = %s' % self.instance_var
print 'self.static_var = %s' % self.static_var
print 'Foo.static_var = %s' % Foo.static_var
f1 = Foo('f1')
f1.printAll()
f1.static_var="Shadowing static_var"
f1.printAll()
f2 = Foo('f2')
f2.printAll()
Foo.static_var="modified class"
f1.printAll()
f2.printAll()
Producción:
self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class
Espero que esto sea útil para alguien.
-
Esta es la respuesta más importante aquí.
– gothz
27 de diciembre de 2021 a las 10:13
neil
además de la respuesta de S. Lott, las variables de clase se pasan a la metaclase nuevo y se puede acceder a través del diccionario cuando se define una metaclase. Por lo tanto, se puede acceder a las variables de clase incluso antes de que se creen e instancian las clases.
por ejemplo:
class meta(type):
def __new__(cls,name,bases,dicto):
# two chars missing in original of next line ...
if dicto['class_var'] == 'A':
print 'There'
class proxyclass(object):
class_var="A"
__metaclass__ = meta
...
...
class User(object):
email="none"
firstname="none"
lastname="none"
def __init__(self, email=None, firstname=None, lastname=None):
self.email = email
self.firstname = firstname
self.lastname = lastname
@classmethod
def print_var(cls, obj):
print ("obj.email obj.firstname obj.lastname")
print(obj.email, obj.firstname, obj.lastname)
print("cls.email cls.firstname cls.lastname")
print(cls.email, cls.firstname, cls.lastname)
u1 = User(email="abc@xyz", firstname="first", lastname="last")
User.print_var(u1)
En el código anterior, la clase Usuario tiene 3 variables globales, cada una con valor ‘ninguno’. u1 es el objeto creado al instanciar esta clase. El método print_var imprime el valor de las variables de clase de la clase Usuario y las variables de objeto del objeto u1. En el resultado que se muestra a continuación, cada una de las variables de clase User.email
, User.firstname
y User.lastname
tiene valor 'none'
mientras que las variables de objeto u1.email
, u1.firstname
y u1.lastname
tener valores 'abc@xyz'
, 'first'
y 'last'
.
obj.email obj.firstname obj.lastname
('abc@xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
En Python, una clase viene con funciones miembro (métodos), variables de clase, atributos/variables de instancia (y probablemente métodos de clase también):
class Employee:
# Class Variable
company = "mycompany.com"
def __init__(self, first_name, last_name, position):
# Instance Variables
self._first_name = first_name
self._last_name = last_name
self._position = position
# Member function
def get_full_name(self):
return f"{self._first_name} {self._last_name}"
Creando una instancia del objeto
my_employee = Employee("John", "Wood", "Software Engineer")
esencialmente desencadenamos __init__
que va a inicializar el variables de instancia de la recién creada Employee
. Esto significa que _first_name
, _last_name
y _position
son parámetros explícitos de lo específico my_employee
instancia.
Igualmente, funciones miembro devolver información o cambiar el estado de una instancia específica.
Ahora cualquier variable definida fuera del constructor __init__
se consideran ser variables de clase. Esas variables se comparten entre todas las instancias de la clase.
john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")
print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)
>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com
También puedes usar métodos de clase para cambiar la variable de clase para todas las instancias de la clase. Por ejemplo:
@classmethod
def change_my_companys_name(cls, name):
cls.company = name
y ahora change_my_companys_name()
bob.change_my_companys_name("mynewcompany.com")
tendrá efecto en todas las instancias de la clase Employee
:
print(bob.company)
print(john.company)
>>> mynewcompany.com
>>> mynewcompany.com
juan viernes
Código de ejemplo:
class inside:
def __init__(self):
self.l = []
def insert(self, element):
self.l.append(element)
class outside:
l = [] # static variable - the same for all instances
def insert(self, element):
self.l.append(element)
def main():
x = inside()
x.insert(8)
print(x.l) # [8]
y = inside()
print(y.l) # []
# ----------------------------
x = outside()
x.insert(8)
print(x.l) # [8]
y = outside()
print(y.l) # [8] # here is the difference
if __name__ == '__main__':
main()
-
Pero si uso L para almacenar un int, puedo cambiar la L incluso por la x exterior, sin cambiar la L de la y exterior…
–Oskar Hofmann
5 de julio de 2021 a las 11:29
Una respuesta detallada con ejemplos en la pregunta duplicada: stackoverflow.com/a/9056994/911945
– Antón Tarasenko
27 oct 2018 a las 15:23