Foros del Web » Programando para Internet » Python »

Clase dentro de clase

Estas en el tema de Clase dentro de clase en el foro de Python en Foros del Web. Hola, soy nuevo en el foro, y en primer lugar me gustaría saludaros a todos. El caso es que estoy desarrollando una aplicación en Python ...
  #1 (permalink)  
Antiguo 14/10/2008, 09:41
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Clase dentro de clase

Hola, soy nuevo en el foro, y en primer lugar me gustaría saludaros a todos.
El caso es que estoy desarrollando una aplicación en Python y tengo una clase definida dentro de otra clase... mi pregunta es: ¿es posible acceder a métodos o atributos de la clase contenedora? Por si no me explico bien, pondré un poco de código...

Código:
class A:
	_init__(self):
		self.atributoA = 1
	class B:
		__init__(self):
			self.atributoB = 2
Lo que yo quería era acceder a atributoA desde B, de manera que el valor fuera diferente en función del objeto clase A que hubiese utilizado para crear al de clase B... ugh, empieza a ser un poco lío, si aun así no se me entiende, decídmelo e intento volver a explicarlo, por favor.
Si alguien sabe la respuesta... ¿que pasaría si, por ejemplo, en la clase B definiera un atributoA?

Muchas gracias, espero que podáis ayudarme.
Un saludo.
  #2 (permalink)  
Antiguo 14/10/2008, 13:29
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

Pues creo que podrías probar esas mismas cosas, ¿no?
Probalo y luego nos contás. Sé que estas cosas se pueden hacer de forma relativamente sencilla en Java, pero nunca lo probé en Python.


Saludos.
  #3 (permalink)  
Antiguo 14/10/2008, 13:51
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Hola, Alvlin, gracias por contestar.
Sí que es verdad que en Java no es nada complicado (estoy mucho más acostumbrado a Java que a Python, pero estoy desarrollando un pequeño trabajo con pygame).
En realidad sí que probé varias cosas, pero no logré lo que quería. Probé algo así:

Código:
a = A()
b1 = A.B()
b2 = a.B()

print b1.atributoA
print b2.atributoA
Ambas instrucciones me daban error; la de b1 es obvio, porque no se ha creado ningun atributoA, pero la de b2 tampoco, aun cuando lo creé desde una instancia de A; si a la clase B le asigno un atributoA y luego lo leo, me lee evidentemente el de la clase B.
Lo que me preguntaba es más bien si había algún modo de acceder al "creador" del objeto (algo así como un "../" ), igual que se puede usar el ".__class__" para obtener la clase y el ".__module__" para obtener el módulo en el que está contenido, pero por lo que he encontrado hasta ahora buscando por ahí y enredando en la consola de Python no he visto nada parecido.

Un saludo.
  #4 (permalink)  
Antiguo 14/10/2008, 18:21
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

El tema de clases anidadas no me quedó claro cuando estudié Java (y eso que al final salvé el SCJP ), así que no logro entender cuál es tu intención.

Si lo explicás con un ejemplo quizás lo entienda. Por lo pronto te comento que Python tiene características de programación funcional, así que quizás lo que necesitás se logra usando una clausura.

Creo que también podrías hacerlo usando propiedades, no tengo mucho tiempo ahora para probarlo pero recuerda que en Python se pueden definir métodos que sustituyan el acceso directo a un atributo, fijate mi primer mensaje en este tema
http://www.forosdelweb.com/f130/get-set-618901/

Quizás puedas definir propiedades en la clase interna para atributos de la exterior. Disculpa que ahora tenga poco tiempo y no pueda probarlo.


Saludos.
  #5 (permalink)  
Antiguo 15/10/2008, 00:48
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Gracias por tus sugerencias, probaré lo que me comentas y si saco algo en claro os lo cuento (bien explicado :D).
  #6 (permalink)  
Antiguo 15/10/2008, 01:27
venkman
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

No me hagas demasiado caso, pero recuerdo haber leído que la clase interna no puede acceder a las propiedades de la clase externa.

De todos modos, no estoy seguro de que tu intención de hacer que la clase interna dependa de la instancia usada para crearla sea del todo una buena idea. ¿Qué es lo que quieres hacer?
  #7 (permalink)  
Antiguo 15/10/2008, 01:54
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Cita:
Iniciado por venkman Ver Mensaje
No me hagas demasiado caso, pero recuerdo haber leído que la clase interna no puede acceder a las propiedades de la clase externa.

De todos modos, no estoy seguro de que tu intención de hacer que la clase interna dependa de la instancia usada para crearla sea del todo una buena idea. ¿Qué es lo que quieres hacer?
Hola venkman.
Te describiré brevemente mi proyecto (es un trabajo para la Universidad): quiero hacer una representación del sistema solar, para lo cual tengo una clase SistemaSolar y dentro de esta una clase para el Sol y otra para los planetas, basicamente. Me empeño en hacer clases anidadas porque, aunque en realidad sólo aparecerá en pantalla un sistema solar, me pareció lógico que si creaba dos sistemas solares cada uno tuviera su propio zoom, color de fondo o posición actual (datos de la clase SistemaSolar a los que tienen que acceder los planetas), y no quería pasar el sistema solar como parámetro al constructor de los planetas o el Sol (no son datos de éstos, según me parece); supongo que podría haberlo hecho de otra forma, pero será por mi costumbre a programar en Java.
Efectivamente estás en lo cierto, venkman, buscando un poco más (y juro que había buscado bastante) encontré una página donde indica que las clases anidadas de Python son como las clases estáticas de Java, esto es, nunca están asociadas a una instancia de un objeto si no al objeto clase al que pertenece, por lo que podemos acceder sólo a los atributos de clase (de nuevo, estáticos en Java), por lo que si hiciera dos sistemas solares ambos tendrían que compartir los mismos datos comunes, puesto que serían datos de la clase. Sin embargo, en la misma página viene la solución al problema:
pyhthon nested class: http://mail.python.org/pipermail/python-list/2005-July/330874.html
Se describe una función que convierte una clase estática en no-estática (tipo Python a tipo Java no estático); la verdad es que no he tenido tiempo a probarlo, pero si el test que viene para probarlo funciona de verdad es justo lo que necesitaba .
Así que nada, al final encontré la solución a mi problema; de todas maneras, gracias a quienes me habéis contestado. Espero que a alguien más le pueda servir de ayuda.

Un saludo.
  #8 (permalink)  
Antiguo 15/10/2008, 06:50
venkman
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

Bueno, lo cierto es que creo que no es problema del lenguaje, yo tampoco en Java optaría por ese tipo de solución. Te comento por qué digo esto.

En primer lugar, me pregunto hasta qué punto lo que necesitas son clases específicas o tan sólo es un contenedor genérico de propiedades, digamos una HashTable que contiene tan sólo unos cuantos valores. Por tu descripción, no veo que vaya a contener ningún tipo de lógica.

Aún así, admitamos que pueda ser una clase particular (llamémosla EstadoVisualizacion, p.ej.). Sin embargo, incluso así, no veo que realmente tenga esa clase interna que acceder a la clase SistemaSolar. ¿Por qué para recuperar el color de fondo debería EstadoVisualizacion acceder a SistemaSolar? ¿No es precisamente el objetivo de EstadoVisualizacion guardar el color de fondo?

Más aún, ¿por qué la necesidad de que sea interna a SistemaSolar si quien dices que va a tener que acceder a ella son los planetas? De hecho, ¿por qué hacerla una clase interna?


No sé, como decía creo que no se trata de un tema de lenguaje, sino más bien que el diseño de la aplicación es lo que no termina de encajar. Y ojo, que no digo que esté mal, sólo que por lo que has descrito yo no lo veo. Si quieres podrías describirlo de forma un poco más concreta y lo hablamos. (Sólo si quieres, eh)
  #9 (permalink)  
Antiguo 15/10/2008, 07:44
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Cita:
Iniciado por venkman Ver Mensaje
Bueno, lo cierto es que creo que no es problema del lenguaje, yo tampoco en Java optaría por ese tipo de solución. Te comento por qué digo esto.

En primer lugar, me pregunto hasta qué punto lo que necesitas son clases específicas o tan sólo es un contenedor genérico de propiedades, digamos una HashTable que contiene tan sólo unos cuantos valores. Por tu descripción, no veo que vaya a contener ningún tipo de lógica.

Aún así, admitamos que pueda ser una clase particular (llamémosla EstadoVisualizacion, p.ej.). Sin embargo, incluso así, no veo que realmente tenga esa clase interna que acceder a la clase SistemaSolar. ¿Por qué para recuperar el color de fondo debería EstadoVisualizacion acceder a SistemaSolar? ¿No es precisamente el objetivo de EstadoVisualizacion guardar el color de fondo?

Más aún, ¿por qué la necesidad de que sea interna a SistemaSolar si quien dices que va a tener que acceder a ella son los planetas? De hecho, ¿por qué hacerla una clase interna?


No sé, como decía creo que no se trata de un tema de lenguaje, sino más bien que el diseño de la aplicación es lo que no termina de encajar. Y ojo, que no digo que esté mal, sólo que por lo que has descrito yo no lo veo. Si quieres podrías describirlo de forma un poco más concreta y lo hablamos. (Sólo si quieres, eh)
¡Claro! Acepto cualquier sugerencia, siempre que haya alguien dispuesto a escucharme . Te lo describiré un poco más en detalle.

No sé si alguna vez has usado pygame, pero supondré que no. Es un framework para desarrollo de aplicaciones multimedia (básicamente, gráficos 2D, sonido y manejo de eventos) en Python, bastante orientado al desarrollo de videojuegos en concreto (y muy recomendable, creo yo).
Hay una clase Sprite pensada para ser extendida, y es base de mis clases Astro y AstroOrbitante (el Sol y los planetas, vaya), donde se define la construcción gráfica de un astro y los movimientos que describe en la pantalla, y hay varias clases para agrupar y manejar con facilidad sprites, una de ellas (la más simple) Group, que es heredada por mi SistemaSolar, el cual maneja cómo se añaden planetas, cuando se actualiza su estado y cuándo se redibujan.
Como en el sistema solar hay cosas muy grandes y muy pequeñas (pensaba poner incluso satélites), mi idea es que se pueda hacer zoom y mover la pantalla (¡mientras que los planetas se mueven, y todo!), así como acelerar o frenar el paso del tiempo para apreciar los movimientos (días/frame, o algo así).
De este modo, todos los planetitas tienen que moverse de acuerdo a una velocidad del tiempo y deben aparecer con un tamaño y en una posición adecuados al zoom actual, y deben borrarse (si has programado algo de gráficos, sabrás que los movimientos pueden verse básicamente como borrar y replicar en otro sitio) con el mismo color de fondo (el negro del espacio, por ejemplo).
De este modo, quizás con algún detalle más que me olvide, hay varios parámetros comunes para todos los planetas; además, tengo en cuenta que un Astro o un AstroOrbitante sólo valen para algo si se los pongo a un sistema solar.

Dicho esto (espero que haya quedado al menos medio claro), quizás por mi formación en programación o quizás por que fue lo primero que se me ocurrió (en realidad, lo segundo o lo tercero), decidí hacer las clases Astro y AstroOrbitante anidadas en SistemaSolar, de modo que un sistema solar contiene astros, es decir, como una manera más "natural" (para mí) de estructurarlo.

Sí que pensé en soluciones que no implicaran esto. Lo primero que se me ocurrió fue definir todos los parametros comunes como externos a cualquier clase (o como propiedades de la clase SistemaSolar; algo global, en cualquier caso), pero esto me impedía tener diferentes sistemas solares independientes, y, aunque sólo voy a hacer uno, no me gustaba (quien sabe, igual un día me da por representar toda la galaxia...).
Otra posibilidad es hacer el sistema solar con sus parámetros y pasar al constructor de los astros el objeto SistemaSolar (habría algún lío con cuál de ellos es el sol, pero bueno, nada difícil de arreglar); esta tampoco me gusta mucho porque no me parece claro que tenga que decir a qué sistema solar pertenece al crearlo, quiero decir que el sistema solar no es una propiedad de un planeta como el radio o la masa, sino que más bien es el contenedor del planeta... no sé, cosas mías.
La tercera opción "extra" que pensé (y, de estas tres, quizás la que más me gusta) es añadir un método a SistemaSolar del tipo "añadePlaneta(self, nombre, masa, radio, ...)" que me añada un planeta directamente al sistema solar; aunque básicamente sería parecida a la anterior, plantea una interfaz más evidente. Sin embargo, no me gusta no poder manipular el objeto antes de añadirlo...

Como ves, en este caso me valdría cualquiera de estas opciones, es todo más bien una cuestión de estilo, costumbre y manías; obviamente, si no hubiese encontrado manera de hacerlo con las clases anidadas lo hubiera hecho de cualquier otra forma, pero lo vi más claro así... Además, era una buena excusa para investigar algo más sobre Python, que es un lenguaje que todavía no conozco demasiado.
Me gustaría que me dijeras, si quieres, cómo lo habrías hecho tú, ya que como todo el mundo sabe hay mil formas de hacer una misma cosa, y probablemente uno nunca encuentra la mejor, de modo que acepto cualquier sugerencia, consejo o crítica .

Un saludo
  #10 (permalink)  
Antiguo 15/10/2008, 09:06
venkman
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

Debo decir que de todas las posibilidades que me comentas, la de hacer clases internas es la que menos me gusta.

Uno de los aspectos más importantes de la orientación a objetos es el de la separación de preocupaciones (separation of concerns) y el desacoplamiento. La idea es que si diseñas un sistema orientado a objetos, las soluciones que debes buscar deben hacer que los objetos sean lo más atómicos posible.

En este caso un Astro (sea un sol o un planeta) es claramente una entidad independiente. Sí, su funcionamiento va a ocurrir dentro de un SistemaSolar, pero la clase Astro en sí debe estar encapsulada de forma independiente. En general el uso de clases internas no suele ser buena idea, pero desde luego no lo es cuando se trata de entidades que tienen una importancia tan grande en el sistema como es, en este caso, Astro.


Yo más bien tendería a la última opción, que SistemaSolar sea un "contenedor de astros". De este modo tendría una colección de planetas. Y claramente tendría una forma de añadir un astro, aunque yo no lo haría como dices, pasándole nombre, radio, masa, etc, sino pasándole un objeto Astro (no me refiero al mismo Astro que tú, luego comento más). Es decir, SistemaSolar no debe instanciar los astros, sólo debe recibirlos.

A nivel de aplicación sería donde haríamos el astro2 = Planeta(nombre, radio, masa...) y luego sistema.addAstro(astro2).

Ahora, ¿por qué digo estas cosas?
La razón principal es esta: Con las clases internas estás ligando mucho las clases de tipo Astro al SistemaSolar. SistemaSolar sólo debería funcionar como un contenedor de Astros, sin tener que ocuparse directamente de cómo es cada Astro. Usando clases internas tendríamos que cada vez que quisieras añadir un tipo de Astro nuevo tendrías que crear una nueva clase interna dentro de SistemaSolar y con toda seguridad hacer cambios en SistemaSolar.

Un nuevo tipo de Astro podría ser uno que tuviera una órbita diferente a la del resto, que girara en sentido contrario por ejemplo o que tuviera una órbita parabólica o hiperbólica (como un asteroide o un cometa quizá) en lugar de elíptica. Y crear algo así no debería afectar a SistemaSolar.

De hecho, lo que debería ser es que SistemaSolar sólo trata con una clase genérica Astro que no es el mismo Astro que tú sino la base de la que deben heredar todos los Astros:

Código python:
Ver original
  1. class Planeta(Astro):
  2.     #...
  3.  
  4. class Sol(Astro):
  5.     #...
  6.  
  7. class Cometa(Astro):
  8.     #...
  9.  
  10. class Sistema:
  11.     #...
  12.     def addAstro(self, astro):
  13.         #...

En caso de añadir ahora un Asteroide, no necesitamos cambiar SistemaSolar para nada, sólo añadir una clase Asteroide que herede de Astro (e implemente los métodos que tiene que implementar cualquier Astro, claro).



Las propiedades que comentas como color de fondo o nivel de zoom, realmente no son una preocupación directa de la que se deban ocupar los planetas. En realidad es algo que concierne únicamente a quien pinta el sistema completo (color de fondo) o a quien toma la decisión de qué planetas pintar. El zoom no le interesa realmente a los planetas. Sino que es el sistema solar el que determina en un momento dado qué planetas deben pintarse o no pintarse y en qué posición. Lo mismo ocurre con el paso del tiempo. Son propiedades que afectan a todo el sistema por igual, no independientemente a cada uno de los planetas y por tanto debe ser preocupación del sistema llamar "más rápido" o "más lento" a que se pinten los planetas (entendiendo por esto no llamarlos más rápido realmente sino contar más rápido el tiempo y calcular las posiciones de los planetas de acuerdo a esa velocidad).


Al final todo se reduce a lo mismo, tratar de separar las preocupaciones y que cada entidad se ocupe sólo de lo que se tiene que ocupar realmente.


Ahora tengo que salir, pero si quieres lo seguimos hablando. bye.
  #11 (permalink)  
Antiguo 15/10/2008, 15:29
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Agradezco tu opinión, venkman, realmente no me lo había planteado como tú dices. Desde ese punto de vista sí se ve muy lógico, pero creo que mi diseño lo he definido un poco forzado por la metodología de pygame, quiero decir, por ejemplo, los astros son sprites, y el modo en que aparecen y se mueven se define dentro de esa clase si queremos que las cosas concuerden, lo que me obliga a que el astro tenga acceso al zoom y a la velocidad de la representación. Seguramente podría haberlo pensado de otro modo si me hubiese ceñido menos a las convenciones de pygame.
Pensaré en adaptarlo a tu modo, aunque creo que eso me va a suponer poco menos que empezar desde cero (bueno, excepto el trabajo de investigación sobre el movimiento de los planetas... ¡era más complicado de lo que pensaba!).
Como he dicho, es sólo un trabajo para la Universidad un poco ambicioso (¡seguro que la mayoría sólo programan un cuadrado dando vueltas! ), pero me gusta al menos intentar hacer las cosas bien... de todos modos, tendré en cuenta lo que me dices para otros proyectos.
  #12 (permalink)  
Antiguo 15/10/2008, 15:35
venkman
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Clase dentro de clase

Bueno, sea como sea, espero que te quede bien bonito y te pongan buena nota :)
  #13 (permalink)  
Antiguo 15/10/2008, 15:45
 
Fecha de Ingreso: octubre-2008
Mensajes: 7
Antigüedad: 15 años, 6 meses
Puntos: 0
Respuesta: Clase dentro de clase

Cita:
Iniciado por venkman Ver Mensaje
Bueno, sea como sea, espero que te quede bien bonito y te pongan buena nota :)
Jajajaja, ¡gracias!
Si lo termino te lo haré saber, a ver si te gusta.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:15.