2010-07-07 20 views
7

Po pierwsze python jest niesamowity język. To mój pierwszy projekt z użyciem Pythona i już osiągnąłem niedorzeczny postęp.jak zrobić ten kod Pythona mniej brzydki

Nie ma możliwości, aby poniższy kod był najlepszym sposobem na zrobienie tego. Jaki jest najbardziej idiomatyczny sposób pisania definicji klasy?

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

Dzięki!

Odpowiedz

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

W ten sposób unika się wielu połączeń do 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

Czy to nie jest ryzykowne? A co, jeśli źle wypiszesz członka w tym ciągu? –

+1

@Assaf Lavie, Tak samo, jak w przypadku błędnego wpisania nazwy atrybutu w kodzie. Tak czy inaczej Python nie będzie narzekał, dopóki nie spróbujesz uzyskać dostępu do nieistniejącego atrybutu. Normalnie powinieneś mieć testy jednostkowe, które wychwycą tego typu błędy. –

2

EDIT: Faktycznie, najlepiej może być:

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

który zakłada zaimportowaniu PyQuery jak PQ. Pozwala to w ogóle uniknąć używania wskaźników.


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

lub jeśli chcesz listowych:

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

ja nie wiem, czy są to najbardziej idiomatyczne, ale jest zdecydowanie mniej boilerplate.

Usuń także crn = course =. Przypisujesz do klasy, a nie do instancji.

+0

Tak myślałem o podobnym roztworze ale nie tak elegancka jak twoja (rozumienie listy zamiast mapy (co jest głupie, gdy myślisz, że mapa jest zdefiniowana w kategoriach rozumienia listy)). – Tyler

+2

Podoba mi się idea lambda, ale nie sądzę, że jest to bardziej czytelne, ponieważ trudno jest zobaczyć, który indeks jest mapowany do którego pola. Wyobraźcie sobie, że musicie dodać gdzieś w środku - łatwo byłoby popełnić błąd. – EMP

+0

@ Evgeny, rozumiem co masz na myśli. Ale ponieważ jest to oparte na skrobaniu strony HTML, jeśli zostanie dodane w środku, pozostałe zostaną przesunięte w dół. Trzeba po prostu umieścić go pomiędzy odpowiednimi dwoma i zwiększyć maksimum. –

2

Nie jestem pewien, czy istnieje "lepszy" sposób. To, co masz, jest z pewnością całkiem czytelne. Jeśli chcesz uniknąć duplikowania kodu Course.get_column, możesz zdefiniować lambdę, tak jak w odpowiedzi Matthew Flaschena, np.

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) 

Należy pamiętać, że nie trzeba wiersz Zainicjowanie wszystkich pól na „” wcześniej - po prostu ustawiając je w __init__ jest w porządku. Edytować: w rzeczywistości, jak Matthew mówi, że ustawia pola klasy, a nie pola instancji - całkowicie to przegapiłem.

4

Osobiście używam słownika zmapować właściwość liczb kolumna:

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

Jedyny możliwy do odczytania kod do tej pory! – Pithikos