Добавить класс Листер


Я чувствую, что нужно переписать довольно большой класс Python, который "делает свое дело", но это выглядит немного страшно, так как он был склеен при изучении Python и платформы приложение Google двигателя. Он работает так, что нет никаких ошибок в сторону пользователя, но читабельность и структура бедных. Это также самый многочисленный класс из всего проекта, что посты сущностей в хранилище данных делают основную функцию "Добавить" для наших предприятий и связанных с кляксами:

class AdLister(FBBaseHandler, I18NHandler): 

    def post(self, view): 
        logging.info('in adlister post')
        message = ''
        challenge = self.request.get('recaptcha_challenge_field').encode('utf-8')
        response  = self.request.get('recaptcha_response_field').encode('utf-8')
        remoteip  = os.environ['REMOTE_ADDR']
        cResponse = captcha.submit(
                     challenge,
                     response,
                     CAPTCHA_PRV_KEY,
                     remoteip)
        if cResponse.is_valid==True:
            isHuman=True
        else:#failed anti-spam test and can try again
            isHuman=False   
            data = AdForm(data=self.request.POST)
            #Reprint the form
            import util
            template_values = {'logo':'montao' if util.get_host().endswith('.br') else 'koolbusiness','isHuman':isHuman,'form':data,'user_url': users.create_logout_url(self.request.uri) if users.get_current_user() else 'login','user' : users.get_current_user(),}
            template_values.update(dict(current_user=self.current_user, facebook_app_id=FACEBOOK_APP_ID))
            template_values.update(dict(capture=captcha.displayhtml(public_key = CAPTCHA_PUB_KEY, use_ssl = False, error = None)))
            path = os.path.join(os.path.dirname(__file__), 'market', 'market_insert.html')
            self.response.out.write(template.render(path, template_values))           
            return            

        from datetime import datetime
        from i18n import FBUser
        from twitter_oauth_handler import OAuthClient
        import random
        twenty = random.randint(1,5) > 3
        def getGeoIPCode(ipaddr):
            from google.appengine.api import memcache
            memcache_key = "gip_%s" % ipaddr
            data = memcache.get(memcache_key)
            if data is not None:
                return data
            geoipcode = ''
            from google.appengine.api import urlfetch
            try:
                fetch_response = urlfetch.fetch('http://geoip.wtanaka.com/cc/%s' % ipaddr)
                if fetch_response.status_code == 200:
                    geoipcode = fetch_response.content
            except urlfetch.Error, e:
                pass
            if geoipcode:
                memcache.set(memcache_key, geoipcode)
            return geoipcode
        path = os.path.join(os.path.dirname(__file__), 'market', 'credit.html') #consume
        lat=0
        lng=0
        try:
            lat = self.request.POST.get('lat')#get lat,lt or latitude
            lng = self.request.POST.get('lng')#get lng, ln or longitude

        except Exception:
            if False:#self.request.POST.get('montao_id'):
                lat=-23.7126
                lng=-46.6415
            else:
                pass
        if False:#self.request.POST.get('montao_id'):
            lat=-23.7126
            lng=-46.6415      
        try:
            ad = Ad(location=db.GeoPt(lat, lng))
            ad.update_location()#also runs this at edits
        except Exception:
            ad = Ad()

        import util          
        if util.get_host().find('koolbusiness') > 0:
            url = 'www.koolbusiness.com'            
        if util.get_host().find('lassifiedsmarket') > 0:
            url = 'classifiedsmarket.appspot.com'        
        if util.get_host().find('montao') > 0 or util.get_host().find('localhost') > 0:
            path = os.path.join(os.path.dirname(__file__), 'market', 'market_ad_preview.html')
            ad.url ='montao'
            logo = 'montao'   

        if (util.get_host().find('acktuellt') > 0 or twenty):
             asked_question = Question(question=self.request.get('title'), asker=db.IM("xmpp", 'classifiedsmarket.appspot.com'))#add urn
             asked_question.put()
             #path = os.path.join(os.path.dirnam e(__file__), 'market', 'market_ad_preview.html')
             if (not twenty or util.get_host().find('acktuellt') > 0):
                ad.published = False             
             path = os.path.join(os.path.dirname(__file__), 'market', 'credit.html') 
        ad.ip = self.request.remote_addr
        ad.ipcountry = getGeoIPCode(self.request.remote_addr)
        if users.get_current_user():
            ad.user = users.get_current_user()
        try:
            ad.type = self.request.POST.get('type')
        except Exception:
            pass
        ad.title = self.request.POST.get('title')
        try:
            ad.text = self.request.POST.get('text')
        except Exception:
            pass
        try:
            ad.currency = self.request.POST.get('currency')
        except Exception:
            pass 
        try:
            ad.facebookID = int(self.current_user.id)
        except Exception, ex:
            logging.debug("failed creating facebookID object for user %s", str(ex))
            pass        

        try:
           client = OAuthClient('twitter', self)
           info = client.get('/account/verify_credentials')
           ad.twitterID = int(info['id'])
        except Exception, ex:
            logging.debug("creating twitter object for user failed %s", str(ex))
            pass      
        try:
            lat = self.request.POST.get('lat')#get lat,lt or latitude
            lng = self.request.POST.get('lng')#get lng, ln or longitude
            ad.geopt = db.GeoPt(self.request.POST.get('lat'),self.request.POST.get('lng'))#above
            ad.geohash = Geohash.encode(float(lat),float(lng), precision=2)#evalu8 precision variable
        except Exception:
            pass
        try:
            ad.category = self.request.POST.get('cg')             
        except Exception:
            logging.error(Exception)
        if self.request.POST.get('company_ad')=='1':
            ad.company_ad = True
        try:
            ad.url=url
        except Exception:
            pass 
        try:
            ad.phoneview = self.request.get('phone_hidden',None) is not None    
        except Exception:
            pass             
        try:
            ad.place = self.request.POST.get('place')
            ad.postaladress = self.request.POST.get('place')
        except Exception:
            pass          
        try:
            ad.name = self.request.POST.get('name')
        except Exception:
            pass 
        try:
            ad.email = self.request.POST.get('email')
        except Exception:
            pass 
        try:
            ad.phonenumber = self.request.POST.get('phonenumber')
        except Exception:
            pass 
        ad.price = self.request.POST.get('price')
        ad.save()        
        self.s = session.Session()
        self.s['key'] = ad.key()         
        def create_image(number, self, file, ad):
            logging.debug('creating image')            
            try:

              file_name = files.blobstore.create()
              with files.open(file_name, 'a') as f:
                  f.write(file)
              files.finalize(file_name)
              blob_key = files.blobstore.get_blob_key(file_name)
              logging.debug('creating image')
              img = Image(reference=ad) 
              logging.debug('creating image')
              img.primary_image = blob_key
              logging.debug('creating image')
              img.put()
              ad.put()
            except Exception:                
               self.response.write(Exception)
               #pass            
            #deprecate see http://stackoverflow.com/questions/5863305/storing-mime-type-with-blobstore
            try:
                filedata = file                
                im = Image(reference=ad)       
                im.full = filedata
                im.small = images.resize(filedata, 640, 480)                 
                tmp=images.Image(im.full)       
                if tmp.width > 80:                
                    im.thumb = images.resize(filedata, 80, 100)#don't if already small                   
                file_name = self.request.POST.get(number).filename                

                im.name = file_name
                im.published    = True
                n = im.name.lower()
                ext = 'jpg'
                for e in ['jpeg','jpg','png','tif','tiff','gif','bmp']:
                    if n.endswith(e):
                        ext=e
                im.full_ext=ext                
                im.small_ext=ext
                im.thumb_ext=ext  
                im.save()       
            except Exception:                
               #self.response.write(Exception)
               pass
        #end deprecate
        try:
            create_image('file', self, self.request.POST.get('file').file.read(), ad)
        except Exception:
            pass      
        try:
            create_image('file2', self, self.request.POST.get('file2').file.read(), ad)
        except Exception:
            pass 
        try:
            create_image('file3', self, self.request.POST.get('file3').file.read(), ad)
        except Exception:
                pass 
        try:   
            create_image('file4', self, self.request.POST.get('file4').file.read(), ad)
        except Exception:
            pass 
        try:
            create_image('file5', self, self.request.POST.get('file5').file.read(),ad)
        except Exception:
                pass         
        try:
            ad.set_password(self.request.POST.get('password'))                 
        except Exception:
            size = 9
            vowels='aeiou'
            consonants='bcdfghjklmnpqrstvwxyz'
            password=''
            from random import randint
            from random import choice
            import random
            minpairs = 4
            maxpairs = 6
            for x in range(1,random.randint(int(minpairs),int(maxpairs))):
                consonant = consonants[random.randint(1,len(consonants)-1)]                      
                if random.choice([1,0]):
                    consonant=string.upper(consonant)
                password=password + consonant
                vowel = vowels[random.randint(1,len(vowels)-1)]
                if random.choice([1,0]):
                    vowel=string.upper(vowel)
                password=password + vowel
                newpasswd = password                                 
            ad.set_password(newpasswd)         
        ad.put()
        key = ad.key()        
        matched_images=ad.matched_images             
        try:    
            im_from = db.IM("xmpp", 'classifiedsmarket.appspot.com')
        except Exception:
            pass    
        #"Added %s."
        msg =  _("Added %s.") % str(ad.title.encode('utf-8'))        
        self.response.out.write(template.render(path, {'url':util.get_host(),'message': msg ,'user':users.get_current_user(),  'ad.user':ad.user,  'ad':ad, 'matched_images':  matched_images,}) )


443
6
задан 17 августа 2011 в 04:08 Источник Поделиться
Комментарии
3 ответа

Первым моим побуждением было бы позаботиться повторять

try:
...
except Exceptiopn:
pass

структуры, которые занимают много места, например

def value_of(self, param):
try:
return self.request.POST.get(param)
except Exception:
return None

...

ad.email = self.value_of('email')

или еще лучше (как это предусмотрено Джеймс Хури):

ad.email = self.request.POST.get(param, None)

и

def create_images(self, ad, *files):
for file in files:
try:
create_image(file, self, self.request.POST.get(file).file.read(),ad)
except Exception:
pass

...

self.create_images(ad, 'file1','file2','file3','file4','file5')

Второе, что я хотел сделать, это попытаться разделить функцию на несколько функций, которые могут быть толково имени. Возможные функции включают в себя


  • generate_password

  • is_submitter_human

  • create_facebook_id

  • create_twitter_id

  • геолокация

Когда основные функции были определены, я хотел бы пойти дальше и попробовать написать функции с точки зрения высшей абстракции, которые используют функции и дал мне прочитать намерения его, как он был исполняемым комментарий.

def post(self, view): 
if not self.is_submitter_human():
return
self.geolocate()
ad = self.create_ad()
self.populate_ad_with_request_parameters(ad)
self.connect_with_facebook(ad)
self.connect_with_twitter(ad)
self.create_images(ad)
self.set_password(ad)
self.save(ad)
self.render(ad);

Отказ от ответственности: я не знаю питон

5
ответ дан 17 августа 2011 в 06:08 Источник Поделиться

Взгляните на Пеп-8. Среди рекомендаций, которые он предлагает, что вы получите все ваши импорта в начала файла. Там даже есть инструмент под названием pep8.py что вы должны работать на ваш код, который предупреждает Вас о некоторые из как отписаться от этих принципов.

Одно замечание, в этой строке:

if cResponse.is_valid==True:

Правда не нужна вообще. Просто оставить его как:

if cResponse.is_valid:

5
ответ дан 17 августа 2011 в 03:08 Источник Поделиться

Начните с написания модульных и/или художественных тестов, которые фиксируют текущее поведение. Затем начать рефакторинг, убедившись в том, что тесты проходят все время.

Если вы не опытный разработчик "рефакторинг", может быть немного размытым, я тогда предлагаю просто начать с устранения дублирования в любой форме нет. Алекси пару примеров извлечения методами. Начнем с этого.

Как вы переместите материал в методы, вы вскоре увидите, что есть разные категории методов, которые используются вместе. Это признак того, что они должны быть перемещены в отдельные классы, чтобы инкапсулировать это поведение.

Тогда читайте о твердых принципах и продолжать оттуда. Практика, практика, практика и подумать о том, что вы делаете во все времена. Удачи!

4
ответ дан 17 августа 2011 в 08:08 Источник Поделиться