Muitas pessoas querem, por diversos motivos, ocultar o código fonte dos seus programas. Muitas acham que compilando o mesmo para bytecode ou binário (nome dado ao bytecode da máquina hospedeira) vão conseguir fazê-lo. Vale lembrar, porém, que existem ''disassemblers'' que conseguem converter para instruções básicas legíveis pelo usuário final e até mesmo alguns que conseguem converter para estruturas de mais alto nível, ficando razoavelmente legível. Tais ''disassemblers'' existem para várias linguagens/bytecodes e o Python não é diferente. O Python utiliza um bytecode para sua própria ''Virtual Machine'' (VM), ao rodar um código legível ('''.py''') ele converte automaticamente para o bytecode e executa-o, sendo que por motivos de desempenho as bibliotecas/módulos são salvos como bytecode para um arquivo, em geral com extensão '''.pyc''' ou '''.pyo''' (otimizado, sem doc-strings). Pode-se, porém, distribuir somente o bytecode e tudo funcionará perfeitamente. Deve ser lembrado que não só é possível como também é fácil transformar o bytecode do Python de volta para um arquivo legível a humanos. Veja http://packages.qa.debian.org/d/decompyle.html . == Como gerar bytecode para o arquivo principal == Ao executarmos um programa python, apenas os módulos importados serão salvos em bytecode, o arquivo principal, o qual foi chamado na linha de comando não. Para convertermos, podemos usar dois métodos: === Trivial === A maneira trivial é fazer ''import'' do seu módulo, para um arquivo chamado {{{meucodigo.py}}}: {{{ python -OO -c "import meucodigo" }}} Esse método tem como efeito colateral que {{{meucodigo}}} é executado e não apenas compilado. === Usando py_compile === O Python provê um módulo para compilar arquivos, é o {{{py_compile}}} [[http://www.python.org/doc/lib/module-pycompile.html]]. ==== Criando um compilador ==== Use o programa {{{pycompiler.py}}}: {{{#!python """ PyCompiler: compile python files to bytecode. Author: Gustavo Sverzut Barbieri License: GPL """ import sys import os import getopt import py_compile import compileall def usage(): print >> sys.stderr, """\ Usage: %s [options] ... where options are: -h, --help This message. -r, --recursive Enter directories recursively. -d, --maxdepth=N Maximum depth in recursion. -f, --force Force recompiling already compiled files. -q, --quiet Be quiet. """ % sys.argv[ 0 ] def compile_file( filename, force=False, quiet=False ): if not quiet: print "Compiling %s ..." % filename py_compile.compile( filename ) def compile_dir( dirname, depth=1, force=False, quiet=False ): compileall.compile_dir( dirname, depth, force=force, quiet=quiet ) def compile( name, depth=1, force=False, quiet=False ): if os.path.isdir( name ): compile_dir( name, depth, force, quiet ) elif os.path.exists( name ): compile_file( name, force, quiet ) else: if not quiet: print >> sys.stderr, "File '%s' doesn't exists!" % name if __name__ == "__main__": try: opts, args = getopt.getopt( sys.argv[ 1: ], "hrd:qf", [ "help", "recursive", "maxdepth=", "quiet", "force" ] ) except getopt.GetoptError: usage() sys.exit( 2 ) depth = 0 quiet = False force = True for o, a in opts: if o in ( "-h", "--help" ): usage() sys.exit( 0 ) elif o in ( "-r", "--recursive" ): if not depth: depth = 20 elif o in ( "-d", "--maxdepth" ): depth = int( a ) elif o in ( "-q", "--quiet" ): quiet = True elif o in ( "-f", "--force" ): force = True for name in args: compile( name, depth, force, quiet ) }}} ==== Linha de comando ==== Caso não queira criar um script para compilar os seus programas, pode usar: {{{ python -OO -c "import py_compile; py_compile.main()" meucodigo1.py meucodigo2.py }}} == Outras Técnicas == Outra técnica para ocultar o código é o '''obfuscamento''', na qual você programa de uma maneira que ninguém entende, ou escreve as partes principais de maneira ilegível, ou que pareça fazer uma coisa e faz outra. Existe obfuscadores de código que pegam as variáveis e dão nomes curtos e sem sentido, como s1, s2, i1, i2, ... e amontoam o código, como {{{for i in [1,2,3]: print i; print i+1}}}.