Aprendiendo Python , y tiene algunas dudas básicas.
1.He visto la declaración de variable (ruta aquí) como
class writer:
path = ""
a veces, no hay declaración explícita, pero se inicializa __init__
.
def __init__(self, name):
self.name = name
Entiendo el propósito de __init__
, pero es recomendable declarar variable en cualquier otra función.
2. ¿Cómo puedo crear una variable para contener un tipo personalizado?
class writer:
path = "" # string value
customObj = ??
__name__
atributo tienen un "nombre". No todos los objetos tienen un__name__
atributo, pero aún puede tener referencias a ellos. Si comenzamos a llamar a una "referencia" un "nombre", estamos haciendo un flaco favor a los principiantes en el futuro.Respuestas:
De acuerdo, lo primero es lo primero.
No existe tal cosa como "declaración de variable" o "inicialización de variable" en Python.
Hay simplemente lo que llamamos "asignación", pero probablemente deberíamos llamar simplemente "nombrar".
Asignación significa "este nombre en el lado izquierdo ahora se refiere al resultado de evaluar el lado derecho, sin importar a qué se refería antes (si acaso)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar' foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar', # and starts being a name for the integer 6, resulting from the multiplication
Como tal, los nombres de Python (un término mejor que "variables", posiblemente) no tienen tipos asociados; los valores lo hacen. Puede volver a aplicar el mismo nombre a cualquier cosa independientemente de su tipo, pero la cosa aún tiene un comportamiento que depende de su tipo. El nombre es simplemente una forma de referirse al valor (objeto). Esto responde a su segunda pregunta: no crea variables para mantener un tipo personalizado. No crea variables para contener ningún tipo en particular. No "crea" variables en absoluto. Le das nombres a los objetos.
Segundo punto: Python sigue una regla muy simple cuando se trata de clases, que en realidad es mucho más consistente que lo que hacen lenguajes como Java, C ++ y C #: todo lo declarado dentro del
class
bloque es parte de la clase . Entonces, las funciones (def
) escritas aquí son métodos, es decir, parte del objeto de la clase (no almacenado por instancia), al igual que en Java, C ++ y C #; pero otros nombres aquí también son parte de la clase. Nuevamente, los nombres son solo nombres y no tienen tipos asociados, y las funciones también son objetos en Python. Así:class Example: data = 42 def method(self): pass
Las clases también son objetos en Python.
Así que ahora hemos creado un objeto llamado
Example
, que representa la clase de todas las cosas que sonExample
s. Este objeto tiene dos atributos proporcionados por el usuario (en C ++, "miembros"; en C #, "campos o propiedades o métodos"; en Java, "campos o métodos"). Uno de ellos se nombradata
y almacena el valor entero42
. El otro se nombramethod
y almacena un objeto de función. (Hay varios atributos más que Python agrega automáticamente).Sin embargo, estos atributos todavía no forman parte del objeto. Básicamente, un objeto es solo un conjunto de más nombres (los nombres de los atributos), hasta que se llega a cosas que ya no se pueden dividir. Por lo tanto, los valores se pueden compartir entre diferentes instancias de una clase, o incluso entre objetos de diferentes clases, si lo configura deliberadamente.
Creemos una instancia:
Ahora tenemos un objeto separado llamado
x
, que es una instancia deExample
. Losdata
ymethod
no son en realidad parte del objeto, pero aún podemos buscarlos a travésx
de algo de magia que Python hace detrás de escena. Cuando miramos hacia arribamethod
, en particular, obtendremos un "método vinculado" (cuando lo llamamos,x
se pasa automáticamente comoself
parámetro, lo que no puede suceder si miramos hacia arribaExample.method
directamente).¿Qué pasa cuando intentamos usar
x.data
?Cuando lo examinamos, primero se busca en el objeto. Si no se encuentra en el objeto, Python busca en la clase.
Sin embargo, cuando asignamos a
x.data
, Python creará un atributo en el objeto. Será no reemplazar el atributo de clase.Esto nos permite realizar la inicialización de objetos . Python llamará automáticamente al
__init__
método de la clase en las nuevas instancias cuando se creen, si están presentes. En este método, simplemente podemos asignar atributos para establecer valores iniciales para ese atributo en cada objeto:class Example: name = "Ignored" def __init__(self, name): self.name = name # rest as before
Ahora debemos especificar un
name
cuando creamos unExample
, y cada instancia tiene el suyoname
. Python ignorará el atributo de claseExample.name
cada vez que busquemos el.name
de una instancia, porque el atributo de la instancia se encontrará primero.Una última advertencia: ¡la modificación (mutación) y la asignación son cosas diferentes!
En Python, las cadenas son inmutables. No se pueden modificar. Cuando tu lo hagas:
a = 'hi ' b = a a += 'mom'
No cambia la cadena 'hola' original. Eso es imposible en Python. En su lugar, crea una nueva cadena
'hi mom'
y hacea
que deje de ser un nombre para'hi '
y comience a ser un nombre para en su'hi mom'
lugar. También hicimosb
un nombre para'hi '
, y después de volver a aplicar ela
nombre,b
sigue siendo un nombre para'hi '
, porque'hi '
todavía existe y no se ha cambiado.Pero las listas se pueden cambiar:
a = [1, 2, 3] b = a a += [4]
Ahora
b
es [1, 2, 3, 4] también, porque hicimosb
un nombre para la misma cosa quea
nombró, y luego cambiamos esa cosa. No creamos una nueva lista paraa
nombrar, porque Python simplemente trata de manera+=
diferente a las listas.Esto es importante para los objetos porque si tuviera una lista como atributo de clase y usara una instancia para modificar la lista, el cambio se "vería" en todas las demás instancias. Esto se debe a que (a) los datos son en realidad parte del objeto de clase y no un objeto de instancia; (b) debido a que estaba modificando la lista y no haciendo una asignación simple, no creó un nuevo atributo de instancia que ocultaba el atributo de clase.
fuente
Esto podría tener un retraso de 6 años, pero en Python 3.5 y superior, declaras un tipo de variable como este:
o esto:
variable_name # type: shinyType
Entonces, en su caso (si tiene una
CustomObject
clase definida), puede hacer:Vea esto o aquello para más información.
fuente
No es necesario declarar nuevas variables en Python. Si hablamos de variables en funciones o módulos, no se necesita declaración. Basta con asignar un valor a un nombre donde lo necesita:
mymagic = "Magic"
. Las variables en Python pueden contener valores de cualquier tipo, y no puede restringir eso.Sin embargo, su pregunta se refiere específicamente a clases, objetos y variables de instancia. La forma idiomática de crear variables de instancia es en el
__init__
método y en ningún otro lugar; aunque puede crear nuevas variables de instancia en otros métodos, o incluso en código no relacionado, es simplemente una mala idea. Hará que su código sea difícil de razonar o de mantener.Así por ejemplo:
class Thing(object): def __init__(self, magic): self.magic = magic
Fácil. Ahora las instancias de esta clase tienen un
magic
atributo:thingo = Thing("More magic") # thingo.magic is now "More magic"
La creación de variables en el espacio de nombres de la clase en sí conduce a un comportamiento completamente diferente. Es funcionalmente diferente y solo debe hacerlo si tiene una razón específica para hacerlo. Por ejemplo:
class Thing(object): magic = "Magic" def __init__(self): pass
Ahora intenta:
thingo = Thing() Thing.magic = 1 # thingo.magic is now 1
O:
class Thing(object): magic = ["More", "magic"] def __init__(self): pass thing1 = Thing() thing2 = Thing() thing1.magic.append("here") # thing1.magic AND thing2.magic is now ["More", "magic", "here"]
Esto se debe a que el espacio de nombres de la clase en sí es diferente al espacio de nombres de los objetos creados a partir de ella. Te dejo a ti investigar un poco más.
El mensaje para llevar a casa es que Python idiomático es (a) inicializar atributos de objeto en su
__init__
método y (b) documentar el comportamiento de su clase según sea necesario. No es necesario que se tome la molestia de obtener documentación completa a nivel de Sphinx para todo lo que escriba, pero al menos algunos comentarios sobre los detalles que usted u otra persona puedan necesitar para recogerlo.fuente
Para fines de alcance, utilizo:
custom_object = None
fuente
Las variables tienen alcance, por lo que sí, es apropiado tener variables que sean específicas de su función. No siempre es necesario ser explícito sobre su definición; por lo general, puede usarlos. Solo si desea hacer algo específico para el tipo de variable, como agregar para una lista, debe definirlos antes de comenzar a usarlos. Ejemplo típico de esto.
list = [] for i in stuff: list.append(i)
Por cierto, esta no es realmente una buena forma de configurar la lista. Sería mejor decir:
list = [i for i in stuff] # list comprehension
...pero yo divago.
Tu otra pregunta. El objeto personalizado debe ser una clase en sí misma.
class CustomObject(): # always capitalize the class name...this is not syntax, just style. pass customObj = CustomObject()
fuente