Paulo Henrique Rodrigues Pinheiro

Um blog sobre programação para programadores!


Lazy evaluation em python com django

Uma experiência frustrada tentando usar Lazy Evaluation no Python, com o framework Django.

Lazy Evaluation Meme

Em Python há uma sutil diferença entre essa construção:


colchetes = [x for x in range(10)]

E essa:


parenteses = (x for x in range(10))

Sutil na sintaxe, mas profunda no que representam.

Inspecionemos a construção com colchetes:


>>> colchetes.__class__
<class 'list'>
>>> colchetes
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

E inspecionemos a com parenteses:


>>> parenteses.__class__
<class 'generator'>
>>> parenteses
<generator object <genexpr> at 0x7f7395b36938>

Em programas simples, elas podem simplesmente ser substituídas por um loop for:


>>> loopfor = []
>>> for x in range(10): loopfor.append(x)
>>> loopfor
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Por curiiosidade, o que é um range afinal?


>>> usandorange = range(10)
>>> l
>>> usandorange
range(0, 10)
usandorange(0, 10)
>>> l[1]
1
>>> usandorange.__class__
<class 'range'>
>>> dir(usandorange)
['__class__', '__contains__', '__delattr__', '__dir__',
 '__doc__', '__eq__', '__format__', '__ge__',
 '__getattribute__', '__getitem__', '__gt__', '__hash__',
 '__init__', '__iter__', '__le__', '__len__', '__lt__',
 '__ne__', '__new__', '__reduce__', '__reduce_ex__',
 '__repr__', '__reversed__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', 'count', 'index', 'start',
 'step', 'stop']

Ainda estou voando. Investigando mais um pouco:


>> print(usandorange.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).

Cheguei a esse código:


def list_posts(request):
    """List posts."""
    try:
        posts = blog.models.Post.objects\
                                .defer('content')\
                                .all()\
                                .order_by('-pub_date')
        data = {
            'status': 'success',
            'message': '',
            'posts': [post_info(request, post) for post in posts],
        }
    except:
        return fail('Internal error. Please, try later.', 503)

    data['posts_count'] = len(data['posts'])

    return JsonResponse(data)