2010-07-07 10 views
7

Vor allem Python ist eine tolle Sprache. Dies ist mein erstes Projekt mit Python und ich habe schon eine Menge Fortschritte gemacht.Wie mache ich diesen Python-Code weniger hässlich

Es gibt keine Möglichkeit, dass dieser Code unten der beste Weg ist, dies zu tun. Was ist die idiomatische Art, eine Klassendefinition zu schreiben?

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() 

Vielen Dank!

Antwort

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)) 

Auf diese Weise vermeidet mehrere Aufrufe 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

Ist das nicht riskant? Was passiert, wenn Sie ein Mitglied in dieser Zeichenfolge falsch schreiben? –

+1

@Assaf Lavie, das gleiche wie wenn Sie einen Attributnamen in Ihrem Code falsch eingeben. In beiden Fällen wird sich Python nicht beschweren, bis Sie versuchen, auf ein nicht vorhandenes Attribut zuzugreifen. Normalerweise sollten Sie Einheitentests haben, die diese Art von Fehlern abfangen würden. –

2

EDIT: Eigentlich könnte das Beste sein:

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')] 

Das setzt voraus, Sie PyQuery als pq importiert haben. Dies vermeidet die Verwendung von Indizes überhaupt.


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)) 

oder wenn Sie wollen eine Liste Verständnis:

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)] 

Ich weiß nicht, ob diese die idiomatische sind, aber es ist auf jeden Fall weniger vorformulierten.

Entfernen Sie auch die crn = course =. Sie ordnen der Klasse und nicht der Instanz zu.

+0

Ja, ich dachte über eine ähnliche Lösung aber nicht ganz so elegant wie deins (liste verständnis statt map auf (was dumm ist, wenn man bedenkt, dass map in begriffen eines listenverständnisses definiert ist)). – Tyler

+2

Ich mag die Lambda-Idee, aber ich glaube nicht, dass dies tatsächlich lesbarer ist, weil es schwer zu erkennen ist, welcher Index zu welchem ​​Feld zugeordnet wird. Stellen Sie sich vor, Sie müssten irgendwo einen in der Mitte hinzufügen - es wäre leicht, einen Fehler zu machen. – EMP

+0

@Evgeny, ich verstehe was du meinst. Da es jedoch auf dem Scraping einer HTML-Seite basiert, werden die anderen nach unten verschoben, wenn eine in der Mitte hinzugefügt wird. Sie müssen es nur zwischen die richtigen zwei setzen und das Maximum erhöhen. –

2

Ich bin mir nicht sicher, ob es einen "besseren" Weg gibt. Was Sie haben, ist sicherlich gut lesbar. Wenn Sie vermeiden wollten, den Code Course.get_column zu duplizieren, könnten Sie dafür ein Lambda definieren, wie in der Antwort von Matthew Flaschen, z.

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) 

Beachten Sie, dass die Linie nicht brauchen, die alle Felder initialisiert auf „“ vorher - nur um sie in __init__ Einstellung ist in Ordnung. Edit: in der Tat, wie Matthew sagt, die Klassenfelder, nicht Instanzfelder setzt - das habe ich total vermisst.

4

Ich persönlich ein Wörterbuch verwenden würde die Eigenschaft Spaltennummern zuzuordnen:

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

Der bisher einzige lesbare Code! – Pithikos

Verwandte Themen