Hack x Crack - Comunidad de Seguridad informática

Programación => Scripting => Python => Mensaje iniciado por: URSS_Lover en Agosto 20, 2017, 01:48:21 am

Título: Clases dentro de clases [Consulta]
Publicado por: URSS_Lover en Agosto 20, 2017, 01:48:21 am
Hola colegas, hoy he estado trasteando con python intentando hacer un programita que no viene al cuento, pero se me ocurrió una solución que me ha desolucionado todo, jajaja, quiero hacer en el programa una clase "entidad", la "entidad" tiene "nombre" y una "posición" en el espacio, pero por comodidad, quería hacer que la "posición" fuera otro objeto, con los atributos "x" y "y", ¿Es posible hacer eso? Basicamente una de las tantas cosas que intenté fué declarar una clase dentro de otra clase, que al llamar la clase mas alta esta llamara a la clase mas baja, pero osea, me lo ejecutó, mas al intentar acceder al clase1.clase2.atributo no me lo reconoce (aunque ojo, si me deja acceder así a la clase2).
Título: Re:Clases dentro de clases [Consulta]
Publicado por: ravenheart en Agosto 20, 2017, 09:04:22 am
¿Cómo lo has hecho? Tendría que funcionar.
Título: Re:Clases dentro de clases [Consulta]
Publicado por: URSS_Lover en Agosto 20, 2017, 06:47:12 pm
Código: Python
  1. class entidad:
  2.         class pos:
  3.                 def __init__(self,x,y):
  4.                         self.x = x
  5.                         self.y = y
  6.                 def mov(self,dim,direccion,i):
  7.                         if (dim == 0) & (direccion == 0): self.x += i
  8.                         elif (dim == 0) & (direccion == 1): self.x -= i
  9.                         elif (dim == 1) & (direccion == 0): self.y += i
  10.                         elif (dim == 1) & (direccion == 1): self.y -= i
  11.                         else: print "Error"
  12.         def __init__(self,identidad,x,y):
  13.                 self.identidad = identidad
  14.                 self.pos(x,y)
  15.         def mov(self,dim,direccion,i):
  16.                 self.pos.mov(dim,direccion,i)

Pero al momento de instanciar un elemento de la clase entidad e intentar acceder a su posición:

Citar
>>> import Cementerio
>>> Kase_o = Cementerio.entidad("Kase",0,0)
>>> Kase_o.pos
<class Cementerio.pos at 0xb729450c>
>>> Kase_o.pos.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class pos has no attribute 'x'
>>> Kase_o.pos.y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class pos has no attribute 'y'
>>>

Cementerio es el archivo en el que tengo la clase, el nombre es simplemente porque allí va todo el codigo disfuncional para hacerle autopsia luego y poder ver qué fue lo que hice mal, jajaja.
Título: Re:Clases dentro de clases [Consulta]
Publicado por: Zarkrosh_7 en Agosto 20, 2017, 07:48:46 pm
Tienes que declarar las clases por separado.

Código: Python
  1. class Motor:
  2.     def __init__(self, potencia):
  3.         self.potencia = potencia
  4.  
  5. class Coche:
  6.     def __init__(self, marca):
  7.         self.marca = marca
  8.         self.motor = Motor(200)
  9.  
  10. coche = Coche("Ford")
  11. print "Marca:", coche.marca
  12. print "Potencia:", coche.motor.potencia
Título: Re:Clases dentro de clases [Consulta]
Publicado por: URSS_Lover en Agosto 20, 2017, 08:34:12 pm
Lo había contemplado como posibilidad, ¿pero entonces lo que intento hacer no es válido? Me ha parecido interesante que a un colega en la universidad le han pedido hacer el tipico programa de gestión de notas a los estudiantes de un aula, me ha parecido que lo mas facil era hacer lo de la clase "aula" y la clase "estudiantes" dentro de la clase "aula", pero bueno... Supongo que no tengo otra opción.
Instanciar una clase como miembro de otra clase... Al final tiene sentido... Bueno, gracias bro. Usaré esa practica.
Título: Re:Clases dentro de clases [Consulta]
Publicado por: deni_celine en Agosto 21, 2017, 03:33:59 am
Si te fijas cuando consultas Kase0.pos te dice que es una clase, no una instancia , independiente si  colocas las dos clases juntas o por separado, lo que tienes que hacer es crear una instancia de la segunda clase.

Ejemplo , podrías tener un attr posición , que instancie una "pos"
Código: [Seleccionar]
self.posicion = self.pos(x,y)
O podrías sobrescribir el attr pos
Código: [Seleccionar]
self.pos = self.pos(x,y)
Título: Re:Clases dentro de clases [Consulta]
Publicado por: URSS_Lover en Agosto 21, 2017, 04:38:18 am
Gracias Deni, he probado lo que me has dicho de instanciar la clase (realmente si me faltó) y sigue sin funcionar:
Citar
Python 2.7.9 (default, Aug 13 2016, 16:41:35)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class auto:
...     class motor:
...             def __init__(self,potencia):
...                     self.potencia = potencia
...     def __init__(self,potencia,marca):
...             self.marca = marca
...             self.potencia = self.motor(potencia)
...
>>> auto
<class __main__.auto at 0xb72e047c>
>>> auto.motor
<class __main__.motor at 0xb72e041c>
>>> iFord = auto(100,"Ford")
>>> iFord.marca
'Ford'
>>> iFord.motor.potencia
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class motor has no attribute 'potencia'
>>> iFord.motor
<class __main__.motor at 0xb72e041c>
>>> iFord.motor(200)
<__main__.motor instance at 0xb72e7d8c>
>>> iFord = iFord.motor(200)
>>> iFord.motor.potencia
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: motor instance has no attribute 'motor'
>>> auto.motor.potencia
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class motor has no attribute 'potencia'
>>>
Nada, pero bueno, a menos lo que ha dicho Zarkrosh me ha servido, es la unica forma que he tenido de ejecutar mi programa.
Título: Re:Clases dentro de clases [Consulta]
Publicado por: ravenheart en Agosto 21, 2017, 05:48:02 pm
Citar
>>> iFord.motor.potencia
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class motor has no attribute 'potencia'

Ten en cuenta que a la instancia de motor dentro de auto la has llamad "potencia":
Código: [Seleccionar]
class auto:
     def __init__(self,potencia,marca):
             self.marca = marca
             ***self.potencia = self.motor(potencia)***

Tendrías que haber hecho:
iFord.potencia.potencia


En cualquier caso, anidar clases no es muy útil salvo para desambiguar (si tuvieras que representar un coche completamente, seguramente necesitarías diferenciar coche.motor de coche.elevalunas.motor, por poner un ejemplo fácil de ver), y para ciertos usos bastante avanzados. Un ejemplo son los iteradores de C++, que se definen en función a tipos parametrizados. Y entonces, no es lo mismo std::vector<int>::iterator que std::vector<std::string>::iterator.


Está bien saber que existen clases anidadas, pero mejor no usarlas, salvo que tengas un buen motivo y sepas lo que estás haciendo.
Título: Re:Clases dentro de clases [Consulta]
Publicado por: URSS_Lover en Agosto 22, 2017, 03:40:05 am
Citar
>>> iFord.motor.potencia
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class motor has no attribute 'potencia'

Ten en cuenta que a la instancia de motor dentro de auto la has llamad "potencia":
Código: [Seleccionar]
class auto:
     def __init__(self,potencia,marca):
             self.marca = marca
             ***self.potencia = self.motor(potencia)***

Tendrías que haber hecho:
iFord.potencia.potencia


En cualquier caso, anidar clases no es muy útil salvo para desambiguar (si tuvieras que representar un coche completamente, seguramente necesitarías diferenciar coche.motor de coche.elevalunas.motor, por poner un ejemplo fácil de ver), y para ciertos usos bastante avanzados. Un ejemplo son los iteradores de C++, que se definen en función a tipos parametrizados. Y entonces, no es lo mismo std::vector<int>::iterator que std::vector<std::string>::iterator.


Está bien saber que existen clases anidadas, pero mejor no usarlas, salvo que tengas un buen motivo y sepas lo que estás haciendo.

Pues al final me ha salido:

Citar
>>> class auto:
...     class motor:
...             def __init__(self,potencia):
...                     self.potencia = potencia
...     def __init__(self,marca,potencia):
...             self.marca = marca
...             self.imotor = self.motor(potencia)
...
>>> iFord = auto("Ford",200)
>>> iFord.marca
'Ford'
>>> iFord.imotor
<__main__.motor instance at 0xb731abec>
>>> iFord.imotor.potencia
200
>>>

Gracias Raven, al final mi error ha sido practicamente el de comerme el punto y coma, en Python. Jajaja. Menudo despiste y lo de anidar clases es mas que todo para experimentar, consideraré lo de no usarlo por norma general.
Por cierto, datos para el que quiera hacer esto. Como al hacer un "self.motor = self.motor(dato)" estaría sobreescribiendo el motor, simplemente lo que estoy haciendo es usar barras bajas para identificar métodos en las clases y clases anidadas y usar nombres sin barras bajas para los miembros normales de una clase. Y ¡Woalah!
Título: Re:Clases dentro de clases [Consulta]
Publicado por: ravenheart en Agosto 22, 2017, 11:33:07 pm
Menudo despiste y lo de anidar clases es mas que todo para experimentar, consideraré lo de no usarlo por norma general.
Tampoco pasa nada si te apetece usarlo, pero no te va a aportar mucho, salvo en los casos que he comentado.