• 03Jul

    Как поменять местами ключи и значения в дикте?

    1. d = {1:2,3:4,5:6}
    2. dict(zip(d.values(),d.keys()))
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]
  • 11Dec

    ai_bolit

    Всем привет. Да, знаю, я давно не писал. Ну простите, и как это не банально, был занят. А заставила меня написать одна мысля. И пожалуйста, дочитайте это до конца, потому что или это очень круто или я опять что то не понимаю, и с температурой 38 мне лучше за клаву не садиться.

    Кеш. Я им пользуюсь для того, чтобы данные, которые я долго вычисляю — положить в память куда нить, чтоб если они понадобились — быстро их оттуда взять. Ну а если их там нет, то просто пересчитать и положить. Если вы им пользуетесь также, то читайте дальше иначе напишите комментарий, который начнется со слов: «Тю, блин, а я его совершенно по другому юзаю, глянь…»

    Т.е. на сетах и гетах все сводится к примерно следующему алгоритму.

    1. from django.core.cache import cache
    2.  
    3. def setter(key,l_value,timeout=0):
    4.     val = cache.get(key)
    5.     if val is None:
    6.         val = l_value()
    7.         cache.set(key,val,timeout)
    8.     return val

    где l_value — это ссылка на функцию, значение которой будет получено, в случае если его нет в кеше.

    Вот этот умопомрачительный алгоритм у меня лежит в основе кеширования.

    Хух… если у вас также, то идете дальше. Надеюсь сейчас осталось достаточно народу.

    Прогуливаясь легкой и непринужденной походкой по блогосфере рунете я уже в который раз натыкаюсь на довольно странное решение следующей проблемы.

    Если есть какие либо данные которые системе нужны часто, но вычисляются долго, то их прямое получение по алгоритму, описанному выше — просто убивает систему. Потому что как только они пропадают из кеша — все, кому нужны эти данные — начинают скопом — все вместе их получать. Например статистика по пользователям у вас вычисляется 5 сек, а выводится на главной странице, с посещаемостью 50 чел в сек, значит одновременно эти данные будут получать 250 процессов – что, может привести к смерти.

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

    Тут просто тьма тьмущая узких мест

    1.Старт у системы должен быть особый. Т.е. в нулевой точке в кеше уже должны быть часто доступные данные.
    2.У вас двойные данные в кеше, т.е. две копии, а ведь часто бывает и такое, что трудновычисляемые данные — это и большие данные.
    3.И последнее — если процесс, который вычисляет заекспаревшиеся данные — умирает. То умирают все. Явно теряем в отказоустойчивости.

    Кратко опишу свой алгоритм решения, и построенный на нем джанговый кешовый бекенд (за базовый взят мемкешовый).

    Если в ячейку с ключем класть не данные, а хеш из двух значений — данные, и время, когда их надо обновить. (ТАДАМ избавились от второго пункта)

    А что если ты перед началом вычислений будеш класть в другой системый и уникальный ключ в кеше время, когда первый, начавший вычисления – планирует их закончить. А остольные процессы, которые захотят получить данные и не увидят их — смогут орентироваться на системный ключь, чтоб понимать, что данные скоро будут и их необходимо подождать или мы не дождались и попробуем еще раз. (ТАДАМ избавились от первого и третьего)

    А теперь скучный код. Чтоб легче было читать — его необходимо скрестить с алгоритмом, который я описывал выше. И если функция гет — вернет None то эти данные сразу начнут вычисляться.

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

    1. from django.core.cache.backends.memcached import CacheClass as BaseCacheClass
    2. from datetime import datetime,timedelta
    3. from time import sleep
    4. from random import random
    5.  
    6. ADDITION_EXP_TIME = 20
    7. TIME_FOR_CREATE = 5
    8.  
    9. class CacheClass(BaseCacheClass):
    10.     def add(self, key, value, timeout=0):
    11.         timeout = timeout or self.default_timeout
    12.         value = {'v':value,'e':datetime.now()+timedelta(seconds=timeout)}
    13.         super(CacheClass,self).add(key,value,timeout+ADDITION_EXP_TIME)
    14.        
    15.     def set(self, key, value, timeout=0):
    16.         timeout = timeout or self.default_timeout
    17.         value = {'v':value,'e':datetime.now()+timedelta(seconds=timeout)}
    18.         super(CacheClass,self).set(key,value,timeout+ADDITION_EXP_TIME)
    19.    
    20.     def get(self,key, default=None):
    21.         wait_next_val = 0
    22.         while True:
    23.             wait_next_val += 0.1
    24.             value = super(CacheClass,self).get(key,default)
    25.             now = datetime.now()
    26.            
    27.             if value is not None and now<value['e']:
    28.                 return value['v']
    29.            
    30.             wait_system_key = 'wait_system__%s__wait_system'%key
    31.             wait_system = super(CacheClass,self).get(wait_system_key)
    32.            
    33.             # if you find expired key first or you don't wait the next person
    34.             if wait_system is None or wait_system<now:
    35.                 super(CacheClass,self).set(wait_system_key,datetime.now()+timedelta(seconds=TIME_FOR_CREATE),TIME_FOR_CREATE + 5)
    36.                 return None
    37.            
    38.             #if somebody already getting a new value
    39.             if value is not None:
    40.                 return value['v']
    41.            
    42.             sleep(random()*wait_next_val)

    И на всякий случай. Если вы все таки считаете это отличной идее. Кладем это в файлик с незамысловатым названием smart_cache.py рядом с settings.py, а в settings.py записываем

    1. CACHE_BACKEND = "smart_cache://127.0.0.1:11211"
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 09Nov

    winpdbХоть простой и нативный pdb и так нам давал все что надо, все же приятно понимать, что есть еще чтото, что может сделать наш девелов приятней. WinPDB – одна из этих приятностей (наткнулся на нее вДжанговкой Вики) . Если коротко – это дебагер с приятным пользовательским интерфейсом, которой кросc-платформенный к слову говоря.

    Пользовать легко.
    Раньше вы коде оставляли:

    1. import pdb; pdb.set_trace()

    А теперь получается чуть длиннее:

    1. import rpdb2; rpdb2.start_embedded_debugger('mysuperpassword')

    На сколько я понял, этот пароль нужен для авторизации дебагера в эту точку прерывания. Т.е. как и pdb, rpdb2 отсанавливает выполение в этой строке.

    Запускаем winpdb. File => Attach. В появившемся окне вводим наш пароль mysuperpassword. В полученном списке выбираем наш.

    Но самое клевое, что теперь мы можем дебагером зацепиться там, где раньше не умели, например wsgi скрипт висит в апаче. Мы можем по средствам этого механизма присосаться и к нему.
    Screenshot-views.py

    P.S. …

    И Django Cheet Sheet, кто еще не знает…
    И надо будет испытать django-tinymce

    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]
  • 01Oct

    Я уже посягал на суверинитет джанги. Но это было давно и не правда. Более того, меня тогда убедили, что делаю я глупости, и я даже убедился сам, в последствии, что на самом деле делаю глупости. Но мысть о том, что urls.py не нужен – не перестает меня беспакоить. Поэтому очередно фин, аморальный бред – называйте как хотите, но мне безумно нравится.

    Идея проста. Вьюха и урла всегда вместе – а значит одно должно быть декоратаром для другого.

    Итак главный urls.py имеет обычный вид

    1. from django.conf.urls.defaults import *
    2.  
    3. urlpatterns = patterns('',
    4.     (r'^someurl/',include('someapp.url_view')),
    5. )

    /someapp/url_view.py – тут у нас сбстно и хранятся вьюхи с урлами. Как видите, декоратор tourl нам земенил запись в urls.py

    1. from django.http import HttpResponse
    2. from tourl import tourl
    3.  
    4. @tourl(r'^and/$')
    5. def and_(request):
    6.     return HttpResponse('and')
    7.  
    8. @tourl(r'^gg/$')
    9. def index(request):
    10.     return HttpResponse('OK')

    /someapp/tourl.py – ну и код самого декоратора

    1. from django.conf.urls.defaults import *
    2. import sys
    3. import functools
    4. def tourl(url_patern,*args,**kwargs):
    5.     def paramed_decorator(func):
    6.         @functools.wraps(func)
    7.         def decorated(self):
    8.             return func(self)
    9.         module =sys.modules[func.__module__]
    10.        
    11.         if not hasattr(module, 'urlpatterns'):
    12.             module.urlpatterns = patterns('',)
    13.              
    14.         module.urlpatterns   += patterns('',
    15.             url(url_patern,decorated,*args,**kwargs),
    16.         )
    17.         return decorated
    18.     return paramed_decorator

    Помоему и симпотично и по производительности не бьет. Вобщем конфетка! Что скажите?

    PS: Добавил снипет.

    PSS: В снипетсах посоветовали добавить functools.wraps

    PSS: А еще можно использовать и так

    1. from django.http import HttpResponse
    2. from tourl import tourl, patterns,url
    3.  
    4.  
    5.  
    6. @tourl(r'^and/$')
    7. def and_(request):
    8.     return HttpResponse('and')
    9.  
    10.  
    11. def index(request):
    12.     return HttpResponse('OK')
    13.  
    14. tourl(r'^gg/$')(index)
    15.  
    16.  
    17. def ordinary(request):
    18.     return HttpResponse('Ordinary')
    19.  
    20. urlpatterns += patterns('',
    21.             url(r'^ord/$',ordinary)
    22.         )
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , , , ,

  • 05Aug
    1. import sys
    2. #from twisted.internet.interfaces import IAddress
    3. name = 'twisted.internet.interfaces.IAddress'
    4.  
    5.  
    6. def import_class(line):
    7.     line = line.split('.')
    8.     mname = '.'.join(line[:-1])
    9.     if mname in sys.modules:
    10.         mname = sys.modules[mname]
    11.     else:
    12.         __import__(mname)
    13.         mname = sys.modules[mname]
    14.     return getattr(mname,line[-1])
    15.  
    16.  
    17. print import_class(name)
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: ,

  • 19May

    как делать group by в моделях. В доках вещь не очевидная. Работает только с транком.

    1. def count_rubrics(post_filters):
    2.     """get dict rubric id => post count if this rubric
    3.    """
    4.     newobj = M.Post.objects.filter(**post_filters).annotate(count_rubric=Count('rubric')).\
    5.              values('rubric','count_rubric')
    6.     newobj.query.group_by = ['rubric_id']
    7.     ret = {}
    8.     for item in newobj:
    9.         ret[item['rubric']] = item['count_rubric']
    10.     return ret
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 07Apr

    Если вы хотите пользоваться всеми переменными окружения Django, но при это “находится” не врутри какой либо вьюхи, т.е. код запускается не через Http запрос, а к примеру – через крон, то начинаться этот скрипт у вас должен такими словами, и лежать он должен в коре вашего проекта:

    1. #!/usr/bin/python
    2. # coding: utf-8
    3. from django.core.management import setup_environ
    4. import settings
    5. setup_environ(settings)

    Успехов…

    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , , ,

  • 14Dec

    Сегодня попробовал, пришел в легкий экстаз….

    В какойнить вьюхе, данные которой вам интересны напишите просто

    1. import pdb
    2. pdb.set_trace()

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

    1. [14/Dec/2008 14:40:21] "GET /myview/ HTTP/1.1" 200 2
    2. > /home/oduvan/www/AppDjango/views.py(10)index()
    3. -> if request.user.is_anonymous:
    4. (Pdb)

    и в консоле поддерживаются следующие основные комманды:
    n – следующая сомманда
    s – зайти в рутину
    r – выйти из рутины
    l [first,[last]] – вывести код, и место, где ты сейчас находишся. Если не указан first и last то выводится текущая позиция. first и last определяет с какой по какую строчки необходимо вывести.
    p – вывести результат операции
    c – продолжать выполнения программы до следующего брейкпоинта
    w – показать текущий стек вызова
    q – выйти.

    Этого мне пока в полне достаточно. Натолкнулся тут. А еще можно почитать на python.org.

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

    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 03Dec

    Буквально пару строк кода добавили массу дополнительных возможностей.

    теперь если функция cp_before возвратит значение – это значит это и будет результатом всего запроса. Появилась функция cp_after которая вызывается в конце всей обработки

    результат работы функций cp__* может быть не обязательно наследник HttpResponse, но и любая другая структура языка, которая уже будет преобразована к оному с помощью функции cp_prepare

    Вот собственно необходимые доработки в классе AddNewUrl :

    1.      def __call__(self,*t,**k):
    2.         if 'before' in self.prefix :
    3.             ret = self.prefix['before'](*t,**k)
    4.             if ret:
    5.                 return ret
    6.         ret =  self.view(*t,**k)
    7.         if 'prepare' in self.prefix:
    8.             newret =   self.prefix['prepare'](ret,*t,**k)
    9.             if newret: ret = newret
    10.         if 'after' in self.prefix:
    11.             self.prefix['after'](*t,**k)
    12.         return ret

    теперь, к примеру задача вывода JSON структуры сводится к

    1. from django.http import HttpResponse
    2. import simplejson as json
    3. class BaseViews(object):
    4.     def prepare_cp(self,response,request):
    5.         return HttpResponse(json.dumps(response))
    6.     def cp__all_rooms(self,request):
    7.         return {'hi':'World','id':request.GET.get('id')}
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , , , ,

  • 01Dec

    Сегодня из интереса написал небольшой модуль сериализации в ХМЛ. На скорую руку. Как по мне – довольно элегантное решение. Как думаете?

    1. def xml_escape(text):
    2.     return str(text).replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace('"','&quot;').replace("'",'&apos;')
    3.  
    4. def xmlSerial(name,attr=None,inner=None):
    5.     if attr:
    6.         name_attr = name+' '+' '.join(map(lambda (a,b):a+'="'+xml_escape(b)+'"',attr.items()))+' '
    7.     else:
    8.         name_attr = name
    9.    
    10.     if inner:
    11.         if type(inner) == list:
    12.             inner_str = ''.join(map(lambda a: xmlSerial(*a),inner))
    13.         else:
    14.             inner_str = inner
    15.         return '<'+name_attr+'>'+inner_str+'</'+name+'>'
    16.     else:
    17.         return '<'+name_attr+'/>'

    Вот, как его мона юзать:

    1. print xmlSerial('HI',{'a':'1','c':3,'d':'WOW'},[['RR'],['WOW',{'and_attr':'45t'}],['WIN',{'a':1},'HI IT IS INNER']])
    2. print xmlSerial('HI',{'a':'1','c':3,'d':'WOW'},[['RR'],['WOW',{'and_attr':'45t'}]])
    3. print xmlSerial('HI',{'a':'1','c':3,'d':'WOW'},[['RR'],['WOW']])
    4. print xmlSerial('HI',{'a':'1','c':3,'d':'WOW'},'AND INNER')
    5. print xmlSerial('HI',{'a':'1','c':3,'d':'WOW'})
    6. print xmlSerial('HI',{'a':'1'})
    7. print xmlSerial('HI')
    Share and Enjoy:
    • Facebook
    • LinkedIn
    • del.icio.us
    • StumbleUpon
    • MySpace
    • Reddit
    • Digg
    • Google Bookmarks
    • Technorati
    • email
    • Print
    • Sphinn
    • Mixx
    • Blogplay
    • Add to favorites
    • Linkter
    • Live
    • MSN Reporter
    • NewsVine
    • RSS
    • Yahoo! Bookmarks
    • Yahoo! Buzz
    • Yigg
    Rating 3.00 out of 5
    [?]

    Tags: , , , ,

« Previous Entries   

Recent Posts

Recent Comments

  • Я просто оставлю это тут: ...
  • спасибо...
  • Если вдуматься в каждое слово, то время беСконечно в русском...
  • Спасибо, Евгений, исправленно.P.S.: перехал на диску...
  • за опечатку - спасибо...