Arquivo da categoria: logica

Encurtador de URL, geração de chaves em python

Ontem estava falando com um colega sobre geração de algo no formato dos encurtadores de URL atuais.
Algo pequeno e único, porém sequencial, para que não fosse necessário ficar verificando no banco a existência de uma chave randômica.

Claro, o que eu fiz é só uma função de teste, e serve para ver que a geração funciona, agora basta a você adaptá-lo ao seu programa caso queira utilizar.

Ainda, como não tenho trabalhado exclusivamente com Python, tenho muita lógica das simples na cabeça. Aquele vai e vem de IFs, e loops, e controles e tal.. mas funciona ! Só que no python sempre tem uma melhor forma de fazer as coisas. E se você sabe como melhorar meu script, poste a solução no comments ou me envie por email, que atualizerei no post. Ok !
Fica ai o desafio…

Ah, no script tem também um print mostrando quantas opções de chaves únicas será possível gerar com os caracteres disponíveis e a quantidade de casas da chave. Ou seja, funciona como nas placas de carro, temos neste caso 62 caracteres disponíveis e geraremos chaves de 5 casas, consequentemente poderemos gerar 916.132.832 chaves diferentes. Já dá bastante neh ! A conta é feita elevanto o numero de caracteres no numero de casas da chave: 62 elevado na 5 (62**5). Se aumentarmos um ou outro teremos mais e mais quantidades de resultados distintos possíveis de serem gerados.

E outro detalhe é que esta função gera resultados SEQUENCIAIS e não randômicos, e a chave disto tudo é a variavel ‘indices’, onde tenho guardado a posição atual de cada casa atualmente. Se você guardar esta variavel em algum lugar e depois reestabelecer seu valor o script funcionará perfeitamente do ponto onde parou. Ok !

Claro, isto é só a geração das chaves, se vc for fazer um encurtador de URL mesmo, necessitará mais do que isto.

#!/usr/bin/env python
"""
Gerador de strings equivalente aos encurtadores de URLs
"""

#Estas variáveis podem ser alteradas conforme desejarem
#Os caracteres possiveis
caracteres = 'A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 0'.split()
#Quantidade de caracteres que terah a chave criada
tamanho = 5

print "Sera possivel gerar", len(caracteres) ** tamanho, "itens diferentes."

#=====================================================================================
#Esta variavel (indices) pode ser guardada e repassada para a função. Ela é o coração da função.
indices = [0 for x in xrange(0,tamanho)]

def gera(texto):
    '''Metodo que gera a chave alphanumerica sequencial'''
    global indices
    url = []
    proximo = False
    #passa o array de traz para frente, verificando se tem como aumentar.
    for x in xrange(tamanho-1, -1, -1):
        proximo = False
        indice = indices[x]
        indice+=1
        if indice >= len(caracteres):
            indice = 0
            proximo = True
            
        indices[x] = indice
        if not proximo:
            break;
    key = []
    for i in indices:
        key.append( caracteres[i] )
    return texto + ''.join(key)


#chamada de exemplo...
for u in xrange(0,7500):
    print gera('http://meu.url/')

Alterando as Tablespaces do Oracle dentro do Dump

Digamos que você tem um dump de Oracle, e que as tabelas estejam na tablespace USERS. E que suas tabelas, ou pelo menos algumas, tenham campos [CB]LOB.
E você quer importar tudo em um novo schema que tem acesso somente a uma outra tablespace, digamos “TS_DADOS”. Quando você for fazer o import com o “IMP” você vai receber um erro dizendo que o schema não tem permissão para gravar em USERS, isto porque os cambos binários não podem ser movimentados de tablespace dentro do banco.

Tah, mas o que isto tem a ver com Python ?

A resolução do problema tem a ver…

O que fazer: Ainda dentro do arquivo de dump do oracle, que é um arquivo com dados binários e strings, antes de efetuar a importação, agente troca o nome da tablespace atual das tabelas, no caso “USERS” para o nome da tablespace que onde queremos que sejam salvos os dados, no caso “TS_DADOS”. Então poderemos importar o dump corretamente.

Eu anteriormente tentei montar um script que alterasse isto para mim dentro do arquivo mais automaticamente, porém não consegui montar algo que prestasse. Tentei com bash, com C, e até Java.. mas quando eu ia importar o dump gerado sempre ocorria algum problema ! haehaehh

Porém por estes dias montei um script em Python que faz isto e simplesmente deu certo… Isto, creio eu, porque a linguagem não faz nada por “debaixo dos panos”, não converte dada, não faz tratamento algum. Faz somente o que eu realmente mando fazer. Lê, altera e grava no novo arquivo.

Simples assim…
Segue o código:

"""
Script que percorre um arquivo e troca as tablespaces erradas dos dumps do Oracle
"""
import sys

if len(sys.argv) < 3:
    print "Informe o arquivo de entrada e de saída!"
    exit()

print "Iniciando conversao do dump..."

f2 = open(sys.argv[2],'w+b')
    
#Estas são as TS que estão incorretas dentro do dump 
tss = ['"USERS"']

with open(sys.argv[1], "r+b") as f:
    for line in f:
        for ts in tss:
            if ts in line:
                line = line.replace(ts,'"TS_DADOS"') #Esta é a TS será utilizada no lugar das incorretas
        f2.write( line )

f2.close()

print "Dump Convertido!"

Parâmetros…

Eu já havia comentado sonbre isto no post sobre Funções, mas agora vou mostrar um exemplo bem simples e prático :

Vejam o código abaixo

#!/usr/bin/python

def func(k,v,d={}):
    d[k]=v
    return d

dic = func('sergio',29)
print dic
dic2 = func('daniella',28)
print dic2
dic3 = func('arthur',4.5,{})
print dic3
dic4 = func('berlotto',65)
print dic4

Antes de mais nada, façam um teste de mesa, e escrevam a saída de dic, dic2, dic3 e dic4 num papel, só depois executem e vejam o resultado!

Agora podem ver a explicação aqui. O problema é como/quando são instanciados os valores para parâmetros com valores default mutáveis em métodos.

Ah, e como dica que veio do blog Programando Python, vocês podem testar este código no Online Python Tutor!

Objetos de Sessão e CherryPy

Por estes dias tive dois percalços no desenvolvimento de um projeto em Django:

1. Qual a “melhor maneira mais rápida” de colocar um pequeno projeto em Django a rodar em produção em uma rede internar ?

Bom, viram que a expressão está entre aspas pois é uma forma de dizer o melhor custo benefício ! hehehe O que ocorria era que eu precisava colocar um pequeno sistema Django no ar, na rede interna, que não dependesse de muitas coisas, principalmente um Apache ou library. Então procurei algumas opções e achei basicamente 1: CherryPy

O CherryPy é um servidor de aplicações puramente Python, e que como vi alguns dizer por ai, é o mais “paythonico” de todos. Cheguei a ele através do django-cpserver, que é um addon aos comandos do manage.py, que roda a aplicação através do WSGI server do CherryPy. Não sei se é a melhor forma de servir meu projeto Django em um servidor interno, que não terá obviamente um acesso quenem o do twitter, mas tento fazer da melhor forma possível

Bom, para funcionar, baixe e instale o CherryPy.

Depois baixe o django-cpserver, e coloque-o em seu PYTHON_PATH ( eu coloquei dentro do diretorio do meu projeto Django ) e adicione-o às INSTALLED_APPS.

Pronto agora basta rodar o comando abaixo para tê-lo rodando via WSGI do CherryPy:

python manage.py runcpserver

Para alterar a porta por exemplo rode:

python manage.py runcpserver port=80

E para mais informações rode:

python manage.py runcpserver help

Aqui e Aqui tem mais informações sobre os frameworks e sobre o CherryPy tb.

2. Como efetuar um redirecionamento nas views do Django passando alguns parametros por POST ?

Descobri que não tem como! Pelo pouco que entendi é inclusive uma restrição do protocolo HTTP e não do Django.

Então, utilizei a sessão para passar algumas informações necessárias na minha view, exemplo uma mensagem…

Vamos ao código:

def index(request):
    #pega o parametro da sessão
    mensagem = request.session.get('mensagem','')
    #retira o parametro da sessão para que não fique para o proximo request
    try:
        del request.session['mensagem']
    except KeyError:
        pass
    #retorna os dados.. no template terá disponível a variavel 'msg' com a mensagem a ser mostrada.
    return render_to_response('index.html', {'msg': mensagem}, context_instance=RequestContext(request))

def salvar_exemplo(request):
    info = Dados.objects.get(id=request.POST['id'])
    #.... tratamento das informações
    request.session['mensagem'] = 'minha mensagem de retorno'
    return HttpResponseRedirect('/index/')

E assim, resolvi meu problema..

Expressão de pesquisa

Com base em um tipo de pesquisa bem interessante que é feito em alguns softwares, resolvi montar o parse para a expressão.
Vou explicar:
Em alguns programas, principalmente na hora de enviar algumas folhas para a impressora, podemos informar 1 ou mais páginas específicas que queremos imprimir. E para isto, podemos utilizar uma notação que seria:

1;3;5 - Imprime as páginas 1, 3 e 5 somente.
5-10  - Imprime todas as páginas de 5 a 10.

Mas eu acrescentei ainda mais um novo item nesta notação, que seria o ‘*’ (asterisco), que tras os numeros daquele tamanho, que iniciem com o numero informado, assim:

9*  - Traz de 90 a 99
94* - Traz de 940 a 949
7** - Traz de 700 a 799

E para brincar um pouco também com a programação funcional. Utiilizando funções lambda, map, xrange e list comprehensions.

Então deixo uma pergunta para quem gosta de melhorar sempre mais e mais seus algoritimos: onde posso utilizar a função ‘filter’ ai neste pequeno trecho de codigo ?

#!/usr/bin/python
# -*- encoding: utf-8 -*-

pesquisa = ';1;3;8-30;99*;4*;'

def montanumeros(v):
    try:
        res = [] #resultado final
        add = lambda x: res.append(x)
        for item in v.split(';'):
            if item.count('-') > 0:
                i,f = map(int,item.split('-'))
                map( add, [ x for x in xrange(i,f+1) ] )
            elif item.count('*') > 0:
                for x in xrange( 0,int('1'+('0'*len(item))) ):
                    if str(x).startswith(item[0:item.index('*')]) and len(str(x)) == len(item):
                        add(x)
            else:
                if item: add(item)
        print res
    except:
        print "Ocorreu algum erro ao tratar a expressao. Verifique!"

montanumeros(pesquisa)

Python com Threads

Hoje em dia, os novos processadores estão com cada vez mais núcleos. Começou no HT, depois 2 núcleos, 3 núcleos, 4 núcleos, e por ai vai…

Por exemplo, aqui na empresa tem uma maquina de 64bits com 8 processadores, mas que naverdade são 2 processadores fisicos com 4 núcleos cada um.

E a indagação que os programas não estão preparados para utilizar todo o poder de processamento das novas máquinas, com vários núcleos. Isto é verdade ? Não sei bem, depende muito.

Acho que o que deve saber de fato utilizar o poder dos núcleos é o sistema operacional. Se este não souber, não há programa que consiga trabalhar bem, mesmo estando preparado. E convenhamos que o nosso kernel linux ( e outros *nix ) sabem fazer muito bem!
Continuar lendo