# -*- coding: iso88591 -*-
# Aula 1 Instrospeção
#
# Observações iniciais: O curso inteiro será baseado em Python.
# eventualmente pode haver comentários sobre Java, mas não sou nenhum
# especialista nas características reflexivas dessa linguagem, 
# principalmente suas versão mais nova.
#
# Usaremos Python 2.3 nesse curso.
#
# Referências:
# http://www-106.ibm.com/developerworks/library/l-pyint.html
# http://diveintopython.org/power_of_introspection/
#
# O que é introspecção: O programa olhando para as suas próprias
# estruturas, descobrindo, em tempo de execução, o seu estado.
#
# Mais formalmente dizemos que introspecção computacional é a capacidade
# de um programa examinar seus objetos e descobrir suas características
# como o que ele é (seu tipo ou classe), o que ele sabe (seu estado, ou
# variáveis membro) e o que ele sabe fazer (a quais métodos ele responde,
# que interfaces implementa).
#
# Esse tipo de capacidade é muito comum em linguagens orientadas a
# objetos. Java é um bom exemplo. Mesmo C++ possui alguma capacidade
# reflexiva.
#
# Vamos ver como instrospecção está presente em Python. Outro objetivo dessa
# primeira aula *recordar* a linguagem. Vou assumir que todos já programaram
# em Python na vida.
#
# 1) Uso do help no interpretador
#

help
help()

# Podemos então brincar um pouco com a ajuda iterativa e descobrir mais
# sobre a linguagem. Por exemplo, podemos descobrir a lista de palavras
# chave da linguagem ou quais modulos estão disponíveis.
#
# >>> keywords
#
# >>> modules
#
# >>> quit
#
# O que ocorre quando pedimos o help de um módulo?
#

help('meu_modulo')

# Olhando o código da do módulo, é fácil imaginar de onde são tiradas
# as informações. Mas como isso é possível?
#
# É claro que se poderia fazer um programa para ler o arquivo e gerar
# a ajuda. Mas em Python essas capacidades estão embutidas, basta usá-las.
# Vamos ver um pouco mais sobre isso.
#
# Vamos começar vendo um pouco o módulo sys, que nos dá informação sobre o
# ambiente de execução.

import sys

print sys.executable
print sys.platform
print sys.version
print sys.maxint

# Observação para o instrutor: Crie um programa bobo que imprime os
# parâmetros e chame-o.
print sys.argv
print sys.path

# Observação para instrutor: Esse talvez fosse mais interessante de ser chamado
# de um interpretador em shell que possui menos módulos carregados

print sys.modules

# Uma outra função pré-definida, muito útil, é a função dir. Ela permite
# descobrir todos os atributos de um objeto, como suas variáveis membro,
# os métodos implementados, etc.

print dir()
print dir(sys)
print dir('')

# O que ocorre se aplicarmos dir a um mpódulo?

print dir('__buildins__')

# Obs: o módulo builtins é um caso gozado. Ele não possui fonte. Na
# veradade ele é gerado pelo shell no início da execução.

# Outros exemplos legais:

print dir(42)
print dir([])
print dir(())
print dir({})
print dir(dir)

# Agora alguns exemplos com a nossa classe

from meu_modulo import *

pedro = Pessoa('Pedro')
cris = Pessoa('Cristina')
cris.outroDado = 23

print dir(pedro)
print dir(cris)

pedro.saudacao()

print dir(pedro.saudacao)

# Um atributo que muitos objetos possuem (em particular: módulos, classes,
# funções e métodos) é o __doc__. Ele deve conter uma string descrevendo
# o objeto (ele é sua documentação). Agora começa a aparecer como o sistema
# de ajudas do python funciona. Vamos ver a cadeia doc do módulo
# __builtins__

print __builtins__.__doc__

# Vamos continuar pelo nossos objetos.

print Pessoa.__doc__

print Pessoa.saudacao.__doc__

# E agora a docstring da função embutida dir

print dir.__doc__

# Agora passemos a instrospecção propriamente dita.
# Como vimos em Python tudo são objectos, mesmo as classes e os módulos,
# bem como as instâncias de classe. Portanto uma API uificada de introspecção
# pode ser usada. Algumas pergutas que podemos querer fazer a um objeto são:

# Qual o seu nome?
# Qual o seu tipo (que tipo de objeto é você)?
# Qual a sua identidade (RG)?
# Quais os seus dados (o que você sabe ou conhece)? Qual o seu estado?
# O que você pode fazer (quais os métodos que você responde)?
# Quam são seus pais (de quais classes essa classe deriva)?

# Vamos lidar com cada uma dessas perguntas.

# Qual o seu nome?

# Os objetos que possuem nome têm também um atributo __name__ que o guarda.
# Vejamos uns exemplos:

print dir()

directory = dir

print directory()

print directory.__name__

# Um valor curioso usado para identificar módulos rodando como
# programa principal.

print __name__

# Qual o seu tipo?

# A função pré-definida type devolve um objeto que representa o
# tipo de seu argumento. Esses objetos podem ser comparados entre
# si para verificar se dois objetos são do mesmo tipo. O módulo
# types possui os objetos que representam os tipos pré-definidos.

import types

print types.__doc__

dir(types)

s = 'uma cadeia de caracteres'

print type(s)

if type(s) is types.StringType: print 's é uma cadeia de caracteres'

print type(42)
print type([])
print type({})
print type(dir)

# Qual o seu RG? Qual a sua identidade?

# Para se obter um número que presenta unicamente cada objeto do sistema
# podemos usar a função pré-definida id.

print id.__doc__

# Vejamos um exemplo interessante.

listaA = [1, 2, 3]
listaB = [1, 2, 3]
listaC = listaB

print listaC
print listaB
print listaA

print id(listaA)
print id(listaB)
print id(listaC)

print listaA is listaB
print listaB is listaC

listaC.append(4)

print listaC
print listaB
print listaA

# Quais os seus dados? Como descobrir os atributos de um objeto.

# Já vimos a função dir que é capaz de listar todos os atributos
# de um objeto. Porém algumas vezes estamos interessados somente em
# verificar se um dado atributo existe e nesse caso manipulá-lo.
# Para isso podemos usar as funções hasattr e getattr

print hasattr.__doc__
print getattr.__doc__

print hasattr(id, '__doc__')
print getattr(id, '__doc__')

# Uma pergunta: como diferenciar métodos de dados? Basta usar a função
# pré-definida callable.

print callable.__doc__

print callable('a string')
print callable(dir)

# Podemos também testar se um objeto é de um certo tipo:

print isinstance.__doc__

print isinstance('uma cadeia', str)
print isinstance('uma cadeira', int)
print isinstance(1.0, float)
print isinstance(1.0, int)

# Verificar se é uma subclasse também dá.

print issubclass.__doc__

class SuperHeroi(Pessoa):
    def saudacao(self):
        '''Mostra educação.
        '''
        
        print 'Olá, sou o super', self.nome, '. Como você se chama?'

print issubclass(SuperHeroi, Pessoa)

print issubclass(Pessoa, SuperHeroi)

print issubclass(SuperHeroi, object)

# Finalmente, colocamos tudo junto na função interroga do módulo
# instroscpeccao. Vamos olhar o seu código e usá-la um pouco.

from introspeccao import *

interroga('string')
interroga(34)
interroga(Pessoa)
interroga(interroga)


syntax highlighted by Code2HTML, v. 0.9.1