2010-07-20 21 views
9

Me doy cuenta de que en la mayoría de los casos, en Python se prefiere simplemente acceder a los atributos directamente, ya que no existe un concepto real de encapsulado como el que hay en Java y similares. Sin embargo, me pregunto si no hay excepciones, especialmente con las clases abstractas que tienen implementaciones dispares.¿Los accesadores en Python están justificados alguna vez?

Digamos que estoy escribiendo un montón de clases abstractas (porque lo soy) y que representan cosas que tienen que ver con los sistemas de control de versiones como repositorios y revisiones (porque lo hacen). Algo así como un SvnRevision y un HgRevision y un GitRevision están estrechamente vinculados semánticamente, y quiero que puedan hacer las mismas cosas (para poder tener código en cualquier otro lugar que actúe sobre cualquier tipo de objeto Repository, y es independiente del subclase), por lo que quiero que hereden de una clase abstracta. Sin embargo, sus implementaciones varían considerablemente.

Hasta ahora, las subclases que se han implementado comparten muchos nombres de atributos, y en una gran cantidad de código fuera de las propias clases, se utiliza el acceso directo a los atributos. Por ejemplo, cada subclase de Revisión tiene un atributo de autor y un atributo de fecha, y así sucesivamente. Sin embargo, los atributos no se describen en ninguna parte de la clase abstracta. Esto me parece un diseño muy frágil.

Si alguien quiere escribir otra implementación de la clase Revision, creo que deberían poder hacerlo simplemente mirando la clase abstracta. Sin embargo, una implementación de la clase que satisfaga todos los métodos abstractos casi seguramente fallará, porque el autor no sabrá que necesitan atributos llamados 'autor' y 'fecha', etc., de modo que el código intenta acceder a Revisión. el autor lanzará una excepción. Probablemente no sea difícil encontrar el origen del problema, pero irritante, sin embargo, y se siente como un diseño poco elegante.

Mi solución fue escribir métodos de acceso para las clases abstractas (get_id, get_author, etc.). Pensé que esta era en realidad una solución bastante limpia, ya que elimina restricciones arbitrarias sobre cómo se nombran y almacenan los atributos, y simplemente deja en claro a qué datos debe acceder el objeto. Cualquier clase que implemente todos los métodos de la clase abstracta funcionará ... se siente bien.

De todos modos, el equipo con el que estoy trabajando odia esta solución (aparentemente por el hecho de que los accesadores son antiponéticos, con lo que realmente no puedo discutir). Entonces ... ¿cuál es la alternativa? ¿Documentación? ¿O el problema que estoy imaginando es un problema?

Nota: He considerado las propiedades, pero no creo que sean una solución más limpia.

+0

"no hay un concepto real de encapsulación"? ¿Qué? Uso encapsulación todo el tiempo en mis diseños. –

+3

La encapsulación es quizás un término sobrecargado. Lo estaba usando ya que se refiere a ocultar información. Los primeros pocos éxitos de google para "encapsulación de python" fueron a lo largo de las líneas de "python no tiene encapsulación", así que me sentí bien al decirlo. – Coquelicot

+0

Si está hablando de variables 'privadas', Python las tiene. Sin embargo, no se usan mucho, ya que no hacen mucho bien. No estoy seguro de qué tipo de "ocultación" está hablando, por lo que probablemente deba proporcionar enlaces, citas y alguna definición de sus términos. –

Respuesta

8

Nota: He considerado las propiedades, pero no creo que sean una solución más limpia.

But they are. Al usar las propiedades, tendrá la firma de clase que desee, y podrá usar la propiedad como un atributo en sí mismo.

def _get_id(self): 
    return self._id 

def _set_id(self, newid): 
    self._id = newid 

Es probable que sea similar a lo que tiene ahora. Para aplacar a su equipo, usted sólo tiene que añadir lo siguiente:

id = property(_get_id, _set_id) 

También es posible usar property como decorador:

@property 
def id(self): 
    return self._id 

@id.setter 
def id(self, newid): 
    self._id = newid 

Y para que sea de sólo lectura, simplemente dejar de lado set_id/la id.setter bit.

1
+0

Gracias, pero eso realmente no aborda mi preocupación (no ser capaz de implementar la clase abstracta simplemente mirando la definición de la clase en sí). Además, para que quede claro, no soy un programador de Java (o C++, o lo que sea) que intenta justificar el uso de códigos idiomáticos de Java en el código de Python. He escrito muy poco Java, y no soy fanático del lenguaje en absoluto. – Coquelicot

+0

El hecho de que el otro idioma en el video sea Java es irrelevante. El uso de acceso directo requiere cambios en el código del cliente, en * cualquier * idioma. –

1

"que debe ser capaz de hacerlo con sólo mirar a la clase abstracta"

No sé lo que esto debe ser cierto. Una "guía de programador", un documento de "cómo extender", más algún entrenamiento me parece apropiado.

"el autor no sabrá que necesitan atributos llamados 'autor' y 'fecha' y así sucesivamente".

En ese caso, la documentación no está completa. Quizás la clase abstracta necesite una mejor docstring. O una "guía de programador" o un documento de "cómo extender".

Además, no parece muy difícil (1) documentar estos atributos en la docstring y (2) proporcionar valores predeterminados en el método __init__.

¿Qué hay de malo en proporcionar soporte adicional para programadores?

Parece que tiene un problema social, no técnico. Escribir código para resolver un problema social parece una pérdida de tiempo y dinero.

+2

Hola, vine aquí para consejos de programación. Si quisiera ser psicoanalizado, iría a FreudOverflow. De todos modos, me gusta la idea de poner documention en el constructor de la clase base como alternativa. – Coquelicot

+1

@ Coquelicot: estoy hablando de desarrollo de software barato, pragmático y de bajo riesgo. Escribir * más * código para "resolver" el problema de otra persona no es un software de alto valor. Educar a otros desarrolladores y escribir menos código reduce los costos y los riesgos. –

4

Te has perdido el punto. No es la falta de encapsulamiento lo que elimina la necesidad de accesadores, sino el hecho de que, al cambiar de un atributo directo a una propiedad, puede agregar un descriptor de acceso en otro momento sin cambiar la interfaz publicada de ninguna manera.

En muchos otros lenguajes, si expone un atributo como público y luego desea envolverlo con algún código en el acceso o la mutación, entonces debe cambiar la interfaz y cualquiera que use el código tiene al menos para recompilar y posiblemente para editar su código también. Python no es así: puedes cambiar el atributo o la propiedad tanto como quieras y ningún código que use la clase se romperá.

0

La discusión ya se terminó hace un año, pero este fragmento parecía delator, vale la pena discutir:

Sin embargo, una implementación de la clase que satisface todos los métodos abstractos es casi seguro que fallar, porque el autor no sabrá que necesitan atributos llamados 'autor' y 'fecha', etc., así que el código que intente acceder a Revision.author arrojará una excepción.

Uh, algo está muy mal. (Lo que dijo S. Lott, menos los comentarios personales). Si estos son miembros necesarios, ¿no están referenciados (si no son necesarios) en el constructor y definidos por docstring? o al menos, como args de métodos requeridos, y otra vez documentado? ¿Cómo pueden saber los usuarios de la clase no cuáles son los miembros requeridos? Para ser el defensor del diablo, ¿qué pasa si su constructor (es) requiere que suministre a todos los miembros que serán/serán necesarios, qué problema causa esto? Además, ¿está verificando los parámetros cuando se aprobaron y lanzando excepciones informativas?

(El argumento ideológico de accessor-vs-property es una barra lateral. Las propiedades son preferibles pero no creo que ese sea el problema con su diseño de clase.)

Cuestiones relacionadas