Mejorar este código

Arnau Sanchez pyarnau en gmail.com
Jue Mayo 8 20:32:06 CEST 2008


eber_ramirez en ltv.org.mx escribió:

> Este es el primer programa que hago en Python, así que agradeceré sugerencias para mejorar el código.
>   

Pues está muy bien para ser tu primera aproximación al lenguaje.

Ya que los pides, aquí van algunos comentarios (la mayoría bastante
establecidos en la "tradición", otros puramente personales):

> # Version 0.1
> # Miercoles 7 de mayo de 2008
> # gerberito en gmail.com
>   

En vez de comentarios, deberías usar las docstring del módulo:

"""
Programa XYZ: Hace esto y lo otro
...

"""

> from Tkinter import *
>   

Es muy común importar los módulos de tkinter de este modo, pero el
principio general es no hacer "from xyz import *", ya que ensucia el
espacio de nombres. Podrías hacer esto:

import Tkinter as tk
tk.Button(...)

> #Creamos la clase que es la base del programa
> class Calcula_MR:
>     def __init__(self):
>         self.CreaObjetos()
>
>     def CreaObjetos(self):
>         self.programa = Tk(  )  # 'Ventana principal' de Tkinter's
>   

Las funciones vacías no deberían llevar espacio en los paréntesis: Tk()

>         self.programa.title ('Momento Resistente - Sin acero a compresion')

No dejes un espacio entre la función y el paréntesis
self.programa.title(...)

>         #MarcoPrincipal=Frame(self.programa)
>         
>         #Primero creamos el cuadro de dialogo para introducir datos.
>         # FR = Factor de reduccion, por default 0.9
>         # b = ancho de la seccion en cm
>         # d = peralte efectivo de la seccion en cm
>         # f'c = resistencia del concreto a la compresion a los 28 dias en kg/cm2
>         # fy = Limite de fluencia del acero en kg/cm2
>         # As = Area de acero en tension en cm2
>   

Como antes: estos comentarios van en los docstrings del método/función.
De esta forma tu aplicación quedará perfectamente documentada.

>         # Ahora creamos las zonas donde el usuario introduce datos
>
>         # Primero ponemos las etiquetas de los datos que ocuparemos
>         fila = 1
>         for label in 'FR ', 'b ', 'd ', 'fc ', 'fy ', 'As ':
>             Etiqueta=Label(self.programa, text=label+'=', borderwidth=6)
>             Etiqueta.grid(row=fila,column=0)
>             #Label(self.programa,text=label+'=', borderwidth=6).grid(row=fila, column=0)
>             fila = fila + 1
>   

Ese uso de "fila" es sospechoso. Usa enumerate:

for fila, label in ("label1", "label2"):
    # fila empieza a contar por 0

Ver de paso Idiomatic Python:

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html

>         #Ahora las unidades en las que se trabaja
>         fila = 1
>         for label in '  ', 'cm ', 'cm ', 'kg/cm2 ', 'kg/cm2 ', 'cm2 ':
>             Etiqueta=Label(self.programa, text=label, borderwidth=6)
>             Etiqueta.grid(row=fila,column=2)
>             #Label(self.programa,text=label, borderwidth=6).grid(row=fila, column=2)
>             fila = fila + 1
>   

Está claro que los nombres y las unidades van unidas, ¿por qué hacer dos
bucles? puedes hacer

for index, (label, unit) in enumerate([("label1", "unit1"), (....)]):

o si quieres manter dos arrays separados, usa zip:

for index, (label, unit) in enumerate(zip(labels, units)):

>         self.FR_t=StringVar()
>         Entry(self.programa, width=10, textvariable=self.FR_t).grid(row=1, column=1)
>         self.FR_t.set('0.9')
>
>         self.b_t=StringVar()
>         Entry(self.programa, width=10, textvariable=self.b_t).grid(row=2, column=1)
>         self.b_t.set('20')
>         
>         self.d_t=StringVar()
>         Entry(self.programa, width=10, textvariable=self.d_t).grid(row=3, column=1)
>         self.d_t.set('40')
>   

Aquí hay un patrón muy claro, deberías crear una lista e iterar en un bucle.

Quizá tengas algún problema al asignar la variable a self, ya que
tendrás el nombre de la variable en una cadena: dale un vistazo a
setattr. Otro tema sería que, en vez de meter esas variables
directamente en la instancia, crearas otra, para separar un poco las cosas:

class Container:
    pass

variables = Container()
variables.d_t = 3

ó si tenemos el nombre de variable en una cadena... s = "d_t", hacemos:

setattr(variables, s, 3)

En este caso puedes acceder a las variables (como cadena) y su valor
pidiendo con "vars" el diccionario de la clase:

vars(variables)

También podrías meterla directamente en un diccionario, pero es
discutible si es estético:

variables["d_t"]

>     def Calculos(self):
>         #Extraemos los datos de los "entry's"
>         FR=float(self.FR_t.get())
>         b=float(self.b_t.get())
>         d=float(self.d_t.get())
>         fc=float(self.fc_t.get())
>         fy=float(self.fy_t.get())
>         As=float(self.As_t.get())
>   

Mucha repetición: puedes abstraerlo en un bucle.

---

Esto en cuanto a lo que atañe al uso del lenguaje. Como concepto general
te recomendaría modularizar: separa la lógica de la presentación
(frontend). Si alguien quiere usar tu script (la parte de cálculo) desde
el suyo propio , o cambiar a gtk, por ejemplo, tendrá que retocarlo
bastante, ya que la interacción con Tk está por todas partes.

A este respecto, y uses el sistema operativo que uses, no dejes de darle
un vistazo a este repaso de la filosofía UNIX:

http://www.faqs.org/docs/artu/ch01s06.html
_______________________________________________
Lista de correo Python-es 
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes





Más información sobre la lista de distribución Python-es