2010-07-07 15 views
7

Primero que nada, Python es un lenguaje impresionante. Este es mi primer proyecto usando Python y ya he hecho una cantidad ridícula de progreso.¿Cómo puedo hacer que este código python sea menos feo

No hay forma de que este código a continuación sea la mejor manera de hacerlo. ¿Cuál es la forma más idiomática de escribir una definición de clase?

class Course: 

    crn = course = title = tipe = cr_hours = seats = instructor = days = begin = end = location = exam = "" 

    def __init__(self, pyQueryRow): 
     self.crn = Course.get_column(pyQueryRow, 0) 
     self.course = Course.get_column(pyQueryRow, 1) 
     self.title = Course.get_column(pyQueryRow, 2) 
     self.tipe = Course.get_column(pyQueryRow, 3) 
     self.cr_hours = Course.get_column(pyQueryRow, 4) 
     self.seats = Course.get_column(pyQueryRow, 5) 
     self.instructor = Course.get_column(pyQueryRow, 6) 
     self.days = Course.get_column(pyQueryRow, 7) 
     self.begin = Course.get_column(pyQueryRow, 8) 
     self.end = Course.get_column(pyQueryRow, 9) 
     self.location = Course.get_column(pyQueryRow, 10) 
     self.exam = Course.get_column(pyQueryRow, 11) 

    def get_column(row, index): 
     return row.find('td').eq(index).text() 

Gracias!

Respuesta

14
def__init__(self, pyQueryRow): 
    for i,attr in enumerate("crn course title tipe cr_hours seats instructor" 
          " days begin end location exam".split()): 
     setattr(self, attr, self.get_column(pyQueryRow, i)) 

De esta manera se evita múltiples llamadas a self.get_column

def__init__(self, pyQueryRow): 
    attrs = ("crn course title tipe cr_hours seats instructor" 
      " days begin end location exam".split()) 
    values = [td.text for td in pyQueryRow.find('td')] 
    for attr, value in zip(attrs, values): 
     setattr(self, attr, value) 
+0

¿No es esto arriesgado? ¿Qué pasa si no escribes mal a un miembro en esa cadena? –

+1

@Assaf Lavie, lo mismo que si escribe mal un nombre de atributo en su código. De cualquier forma, Python no se quejará hasta que intente acceder a un atributo que no existe. Normalmente debe tener pruebas unitarias que detecten esos tipos de errores –

2

EDIT: En realidad, la mejor podría ser:

self.crn, self.course, self.title, self.tipe, self.cr_hours, self.seats,\ 
self.instructor, self.days, self.begin, self.end, self.location, self.exam = \ 
[pq(td).text() for td in pyQueryRow.find('td')] 

que asume que haya importado PyQuery como pq. Esto evita usar índices en absoluto.


self.crn, self.course, self.title, self.tipe, self.cr_hours, self.seats,\ 
self.instructor, self.days, self.begin, self.end, self.location, self.exam = \ 
map(lambda index: get_column(pyQueryRow, index), xrange(0, 12)) 

o si desea una lista de comprensión:

self.crn, self.course, self.title, self.tipe, self.cr_hours, self.seats,\ 
self.instructor, self.days, self.begin, self.end, self.location, self.exam = \ 
[get_column(pyQueryRow, index) for index in xrange(0, 12)] 

No sé si estos son los más idiomática, pero no hay duda menos repetitivo.

Además, quite el crn = course =. Estás asignando a la clase, no a la instancia.

+0

Sí pensé en una solución similar pero no tan elegante como el suyo (liste la comprensión en lugar del mapa (lo cual es tonto cuando considera que el mapa se define en términos de una comprensión de la lista)). – Tyler

+2

Me gusta la idea lambda, pero no creo que sea más legible, porque es difícil ver qué índice se asigna a cada campo. Imagínese si tuviera que agregar uno en el medio en algún lugar; sería fácil cometer un error. – EMP

+0

@Evgeny, entiendo lo que quieres decir. Pero como se basa en el raspado de una página HTML, si se agrega una en el medio, las otras se desplazarán hacia abajo. Solo tiene que ponerlo entre los dos correctos e incrementar el máximo. –

2

No estoy seguro de que haya una "mejor" manera. Lo que tienes es ciertamente bastante legible. Si quería evitar la duplicación del código Course.get_column, podría definir un lambda para eso, como en la respuesta de Matthew Flaschen, por ej.

class Course: 
    def __init__(self, pyQueryRow): 
     get_column = lambda index: pyQueryRow.find('td').eq(index).text() 

     self.crn = get_column(0) 
     self.course = get_column(1) 
     self.title = get_column(2) 
     self.tipe = get_column(3) 
     self.cr_hours = get_column(4) 
     self.seats = get_column(5) 
     self.instructor = get_column(6) 
     self.days = get_column(7) 
     self.begin = get_column(8) 
     self.end = get_column(9) 
     self.location = get_column(10) 
     self.exam = get_column(11) 

Tenga en cuenta que no es necesario la línea que inicializa todos los campos a "" de antemano - sólo colocarlos en __init__ está muy bien. Edit:, de hecho, como dice Matthew, que establece los campos de clase, no los campos de instancia: lo extrañé por completo.

4

En lo personal, me gustaría usar un diccionario para asignar la propiedad a números de columna:

class Course: 

    crn = course = title = tipe = cr_hours = seats = instructor = days = begin = end = location = exam = "" 

    def __init__(self, pyQueryRow): 
     course_row_mapping = { 
      'crn' : 0, 
      'course' : 1, 
      'title' : 2, 
      'tipe' : 3, # You probably mean "type"? 
      'cr_hours' : 4, 
      'seats' : 5, 
      'instructor' : 6, 
      'days' : 7, 
      'begin' : 8, 
      'end' : 9, 
      'location' : 10, 
      'exam' : 11, 
     } 

     for name, col in course_row_mapping.iteritems(): 
      setattr(self, name, Course.get_column(pyQueryRow, col)) 

    def get_column(row, index): 
     return row.find('td').eq(index).text() 
+0

¡El único código legible hasta el momento! – Pithikos

Cuestiones relacionadas