Flet: Exemplo 4

Lista de Tópicos 🖱️

Controles de Layout

Card, Tabs, SafeArea, Divider, VerticalDivider, ExpansionPanelList são outros controles que facilitam a divisão, exibição ou ocultação de conteúdo dentro de uma página de aplicativo.

Seguem-se alguns exemplos de códigos usando esses controles.

Exemplo de uso de Card

Leia sobre a descrição do controle, suas propriedades e evento em Controles de Layout: Card.
O código abaixo exibe a construção de uma página com 3 cards.

import flet as ft

def main(page):
    page.title = "Exemplo usando \"card\""

    listitulo = ft.ListTile(leading=ft.Icon(ft.icons.ACCESS_ALARM,  size=50, color="#D3143E"),
                            title=ft.Text("Compromisso: 28 de junho de 2024"),
                            subtitle=ft.Text("Aniversário de seu filho. Não esqueça o presente!"),)
    
    def apagar(e):
        listitulo.title= ft.Text("")
        listitulo.subtitle=ft.Text("* apagado", color="#aaaaaa")
        cartao.color="WHITE"
        page.update()

    def proximo(e):
        listitulo.title=ft.Text("Compromisso: 01 de agosto de 2024")
        listitulo.subtitle=ft.Text("Viagem para São Paulo", color="#000000")
        cartao.color="#CBEBA8"
        page.update()

    bt1 = ft.TextButton("Apagar", on_click=apagar)
    bt2 = ft.TextButton("Próximo compromisso", on_click=proximo)

    linha = ft.Row([bt1, bt2], alignment=ft.MainAxisAlignment.END)
    coluna = ft.Column([listitulo, linha,])
    contem = ft.Container(coluna, width=500, padding=20,)
    cartao = ft.Card(contem, color="YELLOW", shadow_color="white", elevation=8.0)

    page.add(cartao)

ft.app(target=main)

Na figura 1 o resultado desse código, quando executado.

Figura 1: O Card amarelo mostra o estado incial do app. Card verde, se for clicado “Próximo compromisso”. Último Card, se o clique for no botão “Apagar”.

Tabs

Leia sobre a descrição do controle, suas propriedades e evento em Controle Tabs.

O controle Tabs, usualmente chamado de guias ou abas em português, é usado para separar conteúdo de categorias diferentes, facilitando a navegação do usuário. Ele simula a marcação de bookmarks em um livro físico, para indicar setores de conteúdos diversos, sendo um padrão de desenho com o qual os usuários estão acostumados, no desktop ou web.

Exemplo de uso de Tabs

O código abaixo exibe a construção de uma página o uso de Tabs.

import flet as ft

def main(page: ft.Page):
    page.bgcolor=ft.colors.BROWN_200
    
    ct_interno=ft.Container(content=ft.Text("Conteúdo do Tab 1 dentro de um Card",
                            size=20, weight=ft.FontWeight.BOLD), padding=45)
    
    card = ft.Card(content= ct_interno, elevation=20, expand=1)

    ct_tab1 = ft.Container(content=card, bgcolor="#BAE3ED", alignment=ft.alignment.center)

    tab1 = ft.Tab(text="Tab 1", content=ct_tab1)

    ct_tab2 = ft.Container(content=ft.Text("Conteúdo de texto do Tab 2", size=30),
                           bgcolor="#BBF3EF",
                           margin = ft.margin.all(10.0),
                           padding=ft.padding.all(1.0),
                           alignment=ft.alignment.top_right,
                           border=ft.border.all(2, "#55555"),
                           border_radius=20)

    tab2 = ft.Tab(text="Tab 2", icon=ft.icons.SEARCH, content=ct_tab2)

    ct_tab3 = ft.Container(content=ft.Text("Conteúdo de texto do Tab 3", size=30),
                           bgcolor="#FCF5CC", alignment=ft.alignment.bottom_left)

    tab3 = ft.Tab(text="Tab 3", icon=ft.icons.SETTINGS, content=ct_tab3)

    tabs = ft.Tabs(tabs=[tab1, tab2, tab3],
                   selected_index=0,
                   divider_color="#ABCAD0",
                   label_color="WHITE",
                   unselected_label_color="BLACK",
                   overlay_color = "YELLOW",
                   indicator_padding=10,
                   indicator_color="RED")

    page.add(ft.Container(tabs, bgcolor=ft.colors.BROWN_200, expand=1))

ft.app(target=main)

O resultado desse código está mostrado na figura 2.

Figura 2: Tabs 1, 2 e 3 exibidos, com cliques nas respectivas guias ou abas (tab).

O primeiro tab exibe um card com texto interno, centralizado. O segundo tab tem um container formatado com bordas arredondadas e texto no alto, à direita. O terceiro tab tem texto em baixo, à esquerda.

Observe que no código acima, e na maioria dos blocos de código nessas notas, os controles são montados por partes, separando controles que serão depois inseridos dentro de outros. Para montar o tab1, criamos ct_interno, um container com um texto e o inserimos dentro de card, que é inserido em ct_tab1 e finalmente em tab1. Isso é feito por motívo didático, para que o código fique mais fácil de ser entendido, e não tem efeito no resultado no momento da execução. Esse estilo é uma preferência do programador. Uma forma alternativa para a construção do mesmo controle pode ser vista abaixo.

    tab1 = ft.Tab(
        text="Tab 1",
        content=ft.Container(
            content=ft.Card(
                content=ft.Container(
                    content=ft.Text("Conteúdo do Tab 1 dentro de um Card",
                    size=20, weight=ft.FontWeight.BOLD), padding=45
                ),
                elevation=20, expand=1
            ),
            bgcolor="#BAE3ED",
            alignment=ft.alignment.center
        )
    )

De qualquer forma é importante estabelecer um critério de indentação e se manter coerente com ele.

SafeArea

SafeArea insere conteúdo com preenchimento (padding, as distâncias entre as margens internas do container com as bordas externas do controle) de modo a impedir que os elementos de interface do sistema operacional se sobreponham às do aplicativo. Leia sobre a descrição do controle, suas propriedades em Controles de Layout: SafeAreaCard.

Um exemplo é mostrado no código abaixo.

import flet as ft

class Contador:
    contagem = 0

def main(page: ft.Page):    
    def add_click(e):
        cliques.contagem += 1
        contador.value = f"Contador: {cliques.contagem}"
        contador.update()

    page.horizontal_alignment=ft.CrossAxisAlignment.CENTER
    page.vertical_alignment=ft.MainAxisAlignment.CENTER
    page.floating_action_button = ft.FloatingActionButton(icon=ft.icons.ADD, on_click=add_click)

    cliques = Contador()

    contador = ft.Text("Contador: 0", size=30, color="WHITE", weight=ft.FontWeight.BOLD)

    page.add(
        ft.SafeArea(
            expand=False,
            content=ft.Container(
                content=contador,
                padding=35, width=300, height=190,
                alignment=ft.alignment.center,
                bgcolor="BLUE",
                gradient=ft.LinearGradient(colors=[ft.colors.BLACK, ft.colors.BLUE_900]),
                border=ft.border.all(3, ft.colors.BLUE_100),
                border_radius=ft.border_radius.all(10)
            )
        )
    )

ft.app(main)

A execução desse código gera um aplicativo mostrado na figura 3.

Figura 3: Controle SafeArea tendo um container no seu interior.

Observe que, para manter um contador global foi criada a classe e propriedade State.counter. O objeto cliques = Contador() tem, portanto a propriedade cliques.contagem, que é incrementada a cada clique no botão floating_action_button.

Divider e VerticalDivider

São controles usados para desenhar uma linha divisória, horizontal e vertical, respectivamente. Leia sobre a descrição dos controles e suas propriedades em Controle Divider e VerticalDivider.

import flet as ft

def main(page: ft.Page):
    ct1 = ft.Container(bgcolor="#797EF6", expand=True)
    ct2 = ft.Container(bgcolor="#4ADEDE", expand=True)
    divisorVertical = ft.VerticalDivider(width=50, thickness=10, color="#960cc9")
    ct3 = ft.Container(bgcolor="#1AA7EC", expand=True)
    ct4 = ft.Container(bgcolor="#1E2F97", expand=True)
    divisorHorizontal= ft.Divider(height=50, thickness=40, color="#F6E750")

    page.add(
        ft.Row([ct1, divisorVertical, ct2], spacing=0, expand=True),
        ft.Column([ct3, divisorHorizontal, ct4], spacing=0, expand=True)
    )

ft.app(target=main)

O código executado é renderizado como a figura 4.

Figura 4: Divider e VerticalDivider.

A única diferença entre propriedades de Divider e VerticalDivider são as propriedades Divider.height e VerticalDivider.width.

ExpansionPanel e ExpansionPanelList

ExpansionPanelList é o controle usado para criar painéis expansíveis, que podem ser contraídos até um mínimo, expandidos para exibir conteúdo, ou removidos da página. ExpansionPanelsList recebe uma lista de controles ExpansionPanel. Leia sobre a descrição dos controles e suas propriedades em Controle ExpansionPanelList e ExpansionPanel.

import flet as ft

class Painel(ft.ExpansionPanel):
    def __init__(self, cabecalho, titulo, texto, cor, botao=None, indice=0):
        super().__init__()
        self.can_tap_header=True
        self.bgcolor=cor
        self.header=ft.Text("  " + cabecalho, size=22, weight=ft.FontWeight.BOLD)
        self.titulo=ft.Text(titulo, size=18)
        self.texto=ft.Text(texto, size=17)
        self.conteudo=ft.ListTile(
            title=self.titulo,
            subtitle=self.texto,
            trailing=botao
        )
        self.content=self.conteudo
        self.indice = indice

def main(page: ft.Page):
    cor = [ft.colors.GREEN_100, ft.colors.BLUE_100, ft.colors.RED_100,
           ft.colors.WHITE10, ft.colors.BLUE_500, ft.colors.WHITE70]
    
    def pegar_painel(index):
        for pn in panel.controls:
            if index == pn.indice: return pn
        return None    
            

    def mudou(e: ft.ControlEvent):
        if int(e.data)==4: return
        atividade.conteudo.subtitle.value += f"\nO painel {e.data} foi modificado"
        page.update()

    def apagar(e: ft.ControlEvent):
        pn = pegar_painel(e.control.data)
        if pn:
            panel.controls.remove(pn)
            atividade.conteudo.subtitle.value += f"\nFoi apagado o Painel {e.control.data}"
        page.update()

    panel = ft.ExpansionPanelList(
        elevation=8,
        spacing=6,
        expand_icon_color=ft.colors.AMBER_100,
        divider_color=ft.colors.CYAN_ACCENT_100,
        on_change=mudou
    )
    panel.controls.append(
        Painel("Atividades Online", "Lista das ações realizadas no aplicativo.", "",
               cor[4], None,0
        )
    )
  
    panel.controls.append(
        Painel(
            "Painel 1", "Conteúdo do painel 1", "Clique no ícone para apagar o painel 1.", cor[0],
            ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=1,
            on_click=apagar), 1
        )
    )

    panel.controls.append(
        Painel(
            "Painel 2", "Conteúdo do painel 2", "Clique no ícone para apagar o painel 2.", cor[1],
            ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=2,
            on_click=apagar), 2
        )
    )

    panel.controls.append(
        Painel(
            "Painel 3", "Conteúdo do painel 3", "Clique no ícone para apagar o painel 3.", cor[2],
            ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=3,
            on_click=apagar), 3
        )
    )

    atividade = Painel("Resumo de Atividades", "", "Conteúdo de texto da informação de uso", cor[5])
    panel.controls.append(atividade)

    page.add(panel)

ft.app(target=main)

O resultado pode ser visto na figura 5.

Figura 5: à esquerda o painel com todos os painéis recolhidos. À direita o estado do app após algumas operações de expandir e apagar.

Como são gerados no código vários painéis flet.ExpansionPanel é interessante criar a classe Class Painel que herda de ExpansionPanel, personalizando na inicialização cada caso a ser inserido. O último dos painéis exibidos, atividade é usado para armazenar e exibir as ações feitas no aplicativo, no campo atividade.conteudo.subtitle.value. Essas ações são executadas nos eventos ExpansionPanelList.on_change e pelo clique nos botões ElevatedButton colocados em cada painel, exceto o último, e pela ação de apagar um painel. Os painéis são identificados pela propriedade painel.indice, usada para encontrar e deletar um deles.

Outros controles de Layout

Lista de Tópicos 🖱️

Outros controles de montagem de Layout

Nessa seção veremos os controles Card, Tabs, SafeArea, Divider, VerticalDivider, ExpansionPanelList, todos eles widgets que facilitam a divisão, exibição ou ocultação de conteúdo dentro de uma página de aplicativo.

Card

Um card no flet é um painel de bordas arredondadas e com um sombreado colorido simulando uma elevação sobre o fundo onde está desenhado.

Propriedades de Card

Propriedade Descrição
color indica a cor de fundo do card.
content o controle a ser exibido pelo controle. card só pode ter um filho. Para inserir mais de um widget dentro de card insira nele controles que podem ter vários filhos, como Row, Column ou Stack.
elevation: controla o tamanho da sombra abaixo do card, simulando que esse esteja elevado sobre sua base. O valor default é 1.0.
margin distância entre as bordas e a borda de seu container.
shadow_color cor da sombra abaixo do card.
shape† a forma do card. Esse valor é uma instância de uma das implementações:

  • StadiumBorder
  • RoundedRectangleBorder
    • radius: raio da borda, uma instância da classe BorderRadius ou um número.
  • CircleBorder
  • BeveledRectangleBorder
    • radius: raio da borda, uma instância da classe BorderRadius ou um número.
  • ContinuousRectangleBorder
    • radius: raio da borda, uma instância da classe BorderRadius ou um número.

O formato default é RoundedRectangleBorder com radius=4.0.

surface_tint_color cor usada como sobreposição de cor para indicar elevação.
Se ajustada para None, nenhuma sobreposição será aplicada. Caso contrário, esta cor será composta sobre a cor de fundo com opacidade relacionada à elevação e usada para desenhar fundo do card. O default é None.
† Não consegui usar essa propriedade. Se algum leitor tem essa informação peço que me envie.

Exemplo de uso de Card

Um exemplo mais completo pode ser encontrado em Uso de Card.

import flet as ft

def main(page):
    icon=ft.Icon(ft.icons.ADB_ROUNDED, color=ft.colors.BLUE, size=50 )
    texto1 = ft.Text("Título do Card", size=30)
    texto2 = ft.Text("Conteúdo de texto do Card")
    linha = ft.Row([icon, ft.Column([texto1, texto2])])
    cartao = ft.Card(ft.Container(linha, width=300, padding=20))
    page.add(cartao)

ft.app(target=main)



Como vemos, card tem um único filho, um container que, que sua vez, tem uma linha com um ícone e uma coluna (com dois controles de textos).

Tabs

O controle Tabs, usualmente chamado de guias ou abas em protuguês, é usado para separar conteúdo de categorias diferentes, facilitando a navegação do usuário. Ele simula a marcação de bookmarks em um livro físico, para indicar setores de conteúdos diversos, sendo um padrão de desenho com o qual os usuários estão acostumados, no desktop ou web.

Propriedades de Tabs

Propriedade Descrição
animation_duration tempo de duração, em milisegundos, da animação de trocas entre tabs. O default é 50.
divider_color a cor do divisor entre os tabs ou guias.
indicator_border_radius o raio de arredondadmento de cantos do indicador.
indicator_border_side cor e largura da linha horizontal desenhada abaixo da guia selecionada. Essa linha indica que uma guia está em uso.
indicator_color cor da linha exibida abaixo da guia selecionada.
indicator_padding localiza a linha sublinhada abaixo da guia selecionada, relativa a sua borda. A propriedade indicator_tab_size pode ser usada para indicar a localização das bordas. A propriedade é Falsa para centralizar o conteúdo ou True para usar toda a extensão do tab.
indicator_tab_size booleano, True para que o indicador ocupe todo o tab.
label_color cor dos rótulos das guias selecionadas.
overlay_color define a resposta da cor inicial quando o controle está em foco, hover ou splash. Quando especificada essa propriedade usa MaterialState.FOCUSED, MaterialState.HOVERED ou MaterialState.PRESSED.
selected_index índice do tab selecionado. Pode ser ajustado programaticamente ou selecionado pelo usuário.
scrollable booleano, indica se a barra de tab pode ser rolada horizontalmente. Se scrollable=True cada tab tem a largura necessária para comportar seu rótulo e o controle inteiro é rolável. Se scrollable=False o espaço disponível é distribuído igualmente entre os tabs.
tab_alignment especifica o alinhamento horizontal dos tabs dentro do controle Tabs.
A propriedade TabAlignment é um enum com os valores:

  • NONE
  • START (é o default se scrollable=True)
  • START_OFFSET
  • FILL (é o default se scrollable=False)
  • CENTER
tabs uma lista com os controles tab a serem exibidos.
unselected_label_color a cor das guias (tabs) não selecionadas.

Evento de Tab

Evento Descrição
on_change Dispara quando o índice da guia selecionada (selected_index) é alterado.

Um exemplo de uso de tabs pode ser visto em Uso de Tabs.

Propriedades de Tab

Propriedade Descrição
content o controle a ser exibido quando o Tab é selecionado.
icon ícone a ser exibido à esquerda do texto de Tab.
tab_content um controle com o conteúdo personalizado a substituir o texto e o ícone.
text o nome ou rótulo do Tab.

Divider


Um controle voltado para a diagramação das páginas de aplicativos, desenhando uma linha horizontal externa sobre o container pai, com uma linha interna de mesma extensão mas altura possível diferente. Ele admite preenchimento (padding) em ambas as bordas. Pode ter cor, comprimento e espessura definidas.

Propriedades de Divider

Propriedade Descrição
color cor da linha.
height altura da linha, no sentido horizontal. O centro da linha, desenhada no container, fica no centro de sua altura horizontal. O default é 16.0 se esse valor for null.
thickness espessura da linha desenhada dentro do Divider. Se thickness=0.0 a altura será de 1 pixel. Se esse valor for null esse será 0.0.

Exemplos de uso dos controles Vertical e VerticalDivider podem ser vistos em Uso de Divider.

VerticalDivider

Um controle voltado para a diagramação das páginas de aplicativos, desenhando uma linha vertical sobre o container pai, com exatamente análoga à Divider mas com propriedades cor, largura e espessura. A única propriedade diferente é width que define a largura no sentido horizontal da linha externa.

color cor da linha.
width largura linha externa. O centro da linha, desenhada no container, fica no centro de sua altura horizontal. O default é 16.0 se esse valor for null.
thickness espessura da linha dentro do VerticalDivider. Se thickness=0.0 a altura será de 1 pixel. Se esse valor for null esse será 0.0.

ExpansionPanel e ExpansionPanelList

O controle ExpansionPanelList permite a criação de painéis expansíveis, ou seja, podem ser contraídos até um mínimo, expandidos para exibir conteúdo, ou removidos da página. Como organizador de conteúdo na diagramação de uma interface gráfica ele é similar aos Tabs, mas separando o espaço da página em faixas horizontais. Além disso vários painéis podem ficar simultaneamente abertos.

O controle ExpansionPanelsList recebe uma lista de controles ExpansionPanel.

Propriedades de ExpansionPanelList

Propriedade Descrição
controls uma lista de controles ExpansionPanel a serem exibidos dentro do controle pai.
divider_color a cor do divisor quando ExpansionPanel.expanded=False.
elevation define a elevação dos controles filhos ExpansionPanel quando extendido. O valor default é 2.
expanded_header_padding define o espaçamento interno (padding) em torno da cabeçalho quando extendido. O valor default é padding.symmetric(vertical=16.0). Leia mais sobre padding em Propriedades de Containers.
expanded_icon_color cor do ícone. Default é colors.BLACK_54 em modo de tema claro e colors.WHITE_60 em modo escuro.
spacing tamanho do intervalo entre os ExpansionPanels quando extendidos.

Evento de ExpansionPanelList

on_change dispara quando um ExpansionPanel muda de estado entre expandido e colapsado. A propriedade de evento e.data contem o índice do painel ExpansionPanel que causou o evento.

Propriedades de ExpansionPanel

Os objetos ExpansionPanel são os filhos diretos de ExpansionPanelList, que serão representados na página como painéis extendíveis.

bgcolor a cor de fundo do painel.
content os controles que aparecerão dentro desse painel. Esse conteúdo aparece abaixo do cabeçalho (header) quando o painel está expandido. Se content=None o painel terá um espaço reservado para Texto como conteúdo.
can_tap_header booleano. Se can_tap_header=True um toque sobre o cabeçalho do painel provocará sua expansão ou colapso. Defaults é False.
expanded booleano. Define o estado do painel como expandido ou colapsado. Defaults é False (colapsado).
header o controle a ser apresentado dentro do cabeçalho (header). Se header=None o ExpansionPanel terá terá um espaço reservado para Texto no cabeçalho.

Um exemplo de uso dos controles ExpansionPanelList e ExpansionPanel pode ser visto em Uso de ExpansionPanel.

Bibliografia

Todas as URLs foram visitadas em janeiro de 2024.

Python: Strings e Codificação


Lista de Tópicos 🖱️

Outras informações sobre Strings

Aviso: Se você está lendo essas notas pela primeira vez essas informações podem ser consideradas um pouco complexas. É recomendável que você pule essa seção e volte a ela mais tarde.

Strings são variáveis usadas para armazenar texto. Nessas notas elas já foram estudadas na seção Python: Strings. Algumas informações adicionais podem ser úteis.

Prefixos Modificadores de Strings

Além das strings usuais é possível usar modificadores por meio de prefixos para representar coisas diferentes no Python. As strings resultantes são objetos de string, como qualquer outra string, admitindo seus métodos e propriedades. O prefixo f é o mais comum, permitindo a avaliação de expressões dentro de uma string. Além dele podemos mencionar outros prefixos que podem ser usados sozinhos ou em conjunto:

  • b: bytes literais
  • f: string formatada
  • r: strings brutos
  • u: string usando Unicode legado (PEP 414)

As f-strings são de uso muito comum no Python, que permitindo avaliar expressões dentro de literais de string. As strings brutas não são tão populares quanto as f-strings mas têm seus próprios usos, importantes em certas ocasiões. Resumidamente elas ignoram sequências de escape e retornam texto puro. Strings de bytes são necessárias para armazenar objetos que não contém apenas caracteres mas também códigos de controles e outros valores binários. Unicode legado serve para expressar string em sistemas antigos que ainda não tinham o UTF-8 incorporado.

Strings e bytes

O Python tem o datatype bytes, uma classe diferente das strings.

» string1 = 'Python Pool' 
» print(type(string1))  
↳ <class 'str'>

» string2 = b'Python Pool' 
» print(type(string2)) 
↳ <class 'bytes'>

Método bytes(): O método bytes() converte strings em bytes, retornando um objeto imutável. Seu construtor pode receber o conteúdo da string e sua codificação.

» texto = "Podemos converter strings em bytes"
# converta string em bytes
» texto_to_byte = bytes(texto, 'utf-8')
» print(texto_to_byte)
# Output:
↳ b'Podemos converter strings em bytes'

Lembrando: Nos blocos de código nesse site usamos a notação » para linhas de código, ↳ para resuktados (outputs) e # para comentários do Python.

O método bytes(texto, 'utf-8') converte a string em um objeto bytes usando a codificação utf-8.
Também é possível passar apenas o tamanho da variável, ou uma lista (um iterável):

» tamanho = 7
» bvar = bytes(tamanho)
» print(bvar)
# Output
↳ b'\x00\x00\x00\x00\x00'

» lista = [1, 2, 3, 4, 5]
» bvar = bytes(lista)
» print(bvar)

# Output
↳ b'\x01\x02\x03\x04\x05'

As saídas contém os números de entrada transformados para o formato hexadecimal: 0 &arr;\x00, …, 5 &arr;\x05, etc.

Método decode(): O método inverso, para receber entradas em formato codificado e retornar o argumento decodificado em uma string comum é decode().

» st1 = b'Decodificar \xE2\x9C\x85'
» st2 = b'Decodificar \xE2\x9B\x85'
» print(st1.decode("utf-8"))
↳ Decodificar ✅
» print(st2.decode("utf-8"))
↳ Decodificar ⛅

Nesse caso decode() converteu bytes em strings. Nesse exemplo o código utf-8 \xE2\x9C\x85 representa o sinal ✅ enquanto \xE2\x9B\x85 é o código para o sinal ⛅.

Método chr(): O método chr() converte um inteiro no caracter unicode correspondente.

» print("Usando chr(int):")
» print(f"Maiúsculas: chr(65) = {chr(65)}, ..., chr(90) = {chr(90)}")
» print(f"Minúsculas: chr(97) = {chr(97)}, ..., chr(122) = {chr(122)}")
    
↳ Usando chr(int):
↳ Maiúsculas: chr(65) = A, ..., chr(90) = Z
↳ Minúsculas: chr(97) = a, ..., chr(122) = z

Strings formatadas

Iniciando com o Python 3.12 passou a ser permitido usar strings formatadas, ou f-strings. Elas são uma forma de inserir avaliações de código dentro de texto, concatenando literais de strings com o resultado.

» idade_1 = 15
» idade_2 = 19
» print(f"A idade somada de nossos alunos é {idade_1 + idade_2}, com média {(idade_1 + idade_2)/2}.")
↳ 'A idade somada de nossos alunos é 34, com média 17.0.'

» aluno = {"nome": "Jean Paul", "sobrenome": "Dirac" ,"area": "Física"}
» print(f"Nosso aluno {aluno["nome"]} {aluno["sobrenome"]} se destacou em {aluno["area"]}!")
↳ 'Nosso aluno Jean Paul Dirac se destacou em Física!'

# uma forma mais compacta de conseguir o mesmo resultado consiste em usar 
» aluno = {"nome": "Jean Paul", "sobrenome": "Dirac" ,"area": "Física"}
» print("Nosso aluno {nome} {sobrenome} se destacou em {area}!".format(**aluno))
↳ 'Nosso aluno Jean Paul Dirac se destacou em Física!'


No último exemplo usamos os nomes dos campos diretamente e passamos a string para o método string.format(**aluno). Como argumento o operador ** de desempacotamento (unpacking) retorna os valores do dicionário, ignorando campos extras, caso existam. Essa última forma é mais concisa e legível.

Strings brutas

Strings brutas (raw strings) tem um comportamento igual ao de uma string literal normal, com uma diferença importante: elas ignoram quaisquer sequências de caracteres de escape contidas na string. Por exemplo:

» print("1 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons")
↳ 1 - Componentes do átomo:
       Prótons 
       Nêutrons 
       Elétrons

» print(r"2 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons")
↳ 2 - Componentes do átomo:\n\t Prótons \n\t Nêutrons \n\t Elétrons

No primeiro caso os carateres de controle \n e \t, respectivamente newline e tab, são interpretados como controles. No segundo caso os controles são representados literalmente, como strings.

Se nenhum caracter de controle for encontrado a string fica inalterada com o prefixo r.

» print(r"É muito legal programar com python!" == "É muito legal programar com python!")
↳ True

# mas...
» print(r"10\25\1991" == "10\25\1991")
↳ False

regex
Esse tipo de recurso é particularmente útil quando usamos expressões regulares. Nelas são passadas aos métodos parâmetros com strings incluídas barras invertidas, que têm significado especial para as regex, sem necessidade de escape. Você pode ler sobre as expressões regulares em Expressoes Regulares no Python e, no caso geral, Expressoes Regulares.

Raw strings também auxiliam na construção de caminhos de arquivos e diretórios que contêm barras invertidas que não devem ser “escapadas”. Finalmente elas são úteis para exibir strings com caracteres difíceis de digitar ou ler, caracteres de controle como nova linha ou tabulações.

Codificações de caracteres em Python

Para representar caracteres e sinais de controle no computador diversos sistemas de codificação foram criados. Uma codificação é um sistema de traduzir caracteres (letras, pontuações, símbolos, espaços em branco e controle) para números inteiros e posteriormente para bits.

O mais simples deles é o sistema ASCII, que usa apena 1 byte em toda a sua codificação. Isso pode ser confirmado com a operação:

» all(len(chr(i).encode("ascii")) == 1 for i in range(128))
↳ True

o que mostra que todos os caracteres em chr(i).encode("ascii") com i = 0 … 127 tem comprimento 1.
Tabela ASCII resumida:

Código representa
0 até 31 caracteres de controle, não imprimíveis,
32 até 64 pontuação, símbolos, núeros e espaço,
65 até 90 caracteres maiúsculos do alfabeto inglês,
91 até 96 sinais gráficos como [ \ ] ^ _ `,
97 até 122 caracteres minúsculos do alfabeto inglês,
123 até 126 sinais gráficos adicionais como { | } ~,
127 controle de apagamento (del) não imprimível.
Exibir tabela completa 🖱️

Tabela ASCII completa:

Código representa Código representa
0 NUL (Null) 16 DLE (Data Link Escape)
1 SOH (Start of Heading) 17 DC1 (Device Control 1)
2 STX (Start of Text) 18 DC2 (Device Control 2)
3 ETX (End of Text) 19 DC3 (Device Control 3)
4 EOT (End of Transmission) 20 DC4 (Device Control 4)
5 ENQ (Enquiry) 21 NAK (Negative Acknowledgment)
6 ACK (Acknowledgment) 22 SYN (Synchronous Idle)
7 BEL (Bell) 23 ETB (End of Transmission Block)
8 BS (Backspace) 24 CAN (Cancel)
9 HT (Horizontal Tab) 25 EM (End of Medium)
10 LF (Line Feed) 26 SUB (Substitute)
11 VT (Vertical Tab) 27 ESC (Escape)
12 FF (Form Feed) 28 FS (File Separator)
13 CR (Carriage Return) 29 GS (Group Separator)
14 SO (Shift Out) 30 RS (Record Separator)
15 SI (Shift In) 31 US (Unit Separator)
32 SP (Space)
Código representa Código representa Código representa Código representa
33 ! 44 , 55 7 91 [
34 “ 45 – 56 8 92 \
35 # 46 . 57 9 93 ]
36 $ 47 / 58 : 94 ^
37 % 48 0 59 ; 95 _
38 &er; 49 1 60 < 96 `
39 ‘ 50 2 61 = 97 a 122 a – z
40 ( 51 3 62 >> 123 {
41 ) 52 4 63 ? 124 |
42 * 53 5 64 @ 125 }
43 + 54 6 65 a 90 A – Z 126 ~
127 DEL (delete)

No entanto, o sistema de codificação ASCII permite apenas o mapeamento de 127 sinais ou controles. Ele é pequeno demais para representar a variedade de caracteres acentuados, além daqueles usados em outras línguas como chinês e russo. Por isso se desenvolveu um sistema capaz de representar um conjunto muito maior de caracteres e sinais, de denominado Unicode. Muitos outros sistemas foram criados entes dele mas é predominante, hoje o uso do Unicode e um de seus esquemas de codificação, o UTF-8. Por motivo de compatibilidade os primeiros 127 códigos coicidem com os do ASCII


​
O Unicode não é um sistema de codificação mas engloba vários deles. Ele mapeia caracteres como “a”, “¢” ou “😎”, incluindo emojis. Ele contém praticamente todos os caracteres necessários para uma comunicção moderna internacional, incluindo a marca (código 8207) que indica que o texto será exibido da direita para a esquerda, usado em línguas árabes.

UTF-8: Para representar essa diversidade de caracteres, sinais e controles surgiu o UTF-8, que usa mais de 1 bite na codificação. Seu código tem comprimento variável para cada sinal, podendo chegar a até 4 bites. Por default o Python usa a codificação utf-8.

O código abaixo mostra um caracter, um emoji, com comprimento 4 nessa codificação.

» emoji = "🤨"
» print(len(emoji))
↳ 1
» print(emoji.encode("utf-8"))
↳ b'\xf0\x9f\xa4\xa8'
» print(len(ibrow.encode("utf-8")))
↳ 4

# construir uma lista com objeto de bytes retorna
# o valor decimal para cada byte
» print(list(b'\xf0\x9f\xa4\xa8'))
↳ [240, 159, 164, 168]

Nota, é importante lembrar: o comprimento de um único caracter em unicode no Python é 1, mesmo que ele ocupe vários bites. O comprimento desse caracter codificado em bytes será entre 1 e 4, no UTF-8.

Funções associadas do Python

O Python tem várias funções internas (built-in) associadas com systemas de numeração e codificação de caracteres:

Função retorna
ascii(objeto) string, representação ASCII do objeto com caracteres não-ASCII escapados,
bin(inteiro) string, representação binária do inteiro com prefixo “0b”,
bytes(iterável) converte para bytes, dados binários brutos,
chr(inteiro) string, caracter unicode,
hex(inteiro) string, representação hexadecimal com prefixo “0x”,
int(número) inteiro, converte para inteiro,
oct(número) inteiro, converte para número octal com prefixo “0o”,
ord(string) inteiro, converte caracter unicode para inteiro,
str(objeto) converte para string, texto.

Alguns exemplos:

» print(ascii("jalapeño"))
↳ "'jalape\\xf1o'"

» print(bin(400))
↳ '0b110010000'

» print(bytes(range(97, 123)))  # Iterável de inteiros
↳ b'abcdefghijklmnopqrstuvwxyz'

» print(chr(1114111))
↳ '\U0010ffff'

» print(hex(100))
↳ '0x64'

» print(int('11', base=2))
↳ 3

» print(ord("a"))
↳ 97

» print(str(5))
↳ '5'

» print(str(0xc0ffee))
↳ '12648430'

Módulo String

O Módulo de Strings vem pre-instalado no Python, contendo constantes e método úteis, e duas classes.

String, constantes:

» import string

# string module constants
» print(string.ascii_letters)
↳ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

» print(string.ascii_lowercase)
↳ abcdefghijklmnopqrstuvwxyz

» print(string.ascii_uppercase)
↳ ABCDEFGHIJKLMNOPQRSTUVWXYZ

» print(string.digits)
↳ 0123456789

» print(string.hexdigits)
↳ 0123456789abcdefABCDEF

» print(string.whitespace)  # ' \t\n\r\x0b\x0c'

» print(string.punctuation)
↳ !"#$%&'()*+,-./:;?@[\]^_`{|}~

Método capwords(): O módulo possui um único método, capwords(texto, sep=None). Ela quebra a string em texto, transforma em maiúscula a primeira letra de cada palavra e as junta na string de retorno. Se o argumento opcional sep="None" espaços em branco nas extremidaddes são removidos. Se outro sep é fornecido ela é usado para quebrar o texto original.

» import string
» texto = "  venha aprender o \n\n python  "
» print(string.capwords(texto))
↳ "Venha Aprender O Python"

Classe Formatter: O módulo string possui também duas classes. A classe Formatter tem o mesmo comportamento que string.format() mas é útil para ser herdada em uma classe nova do usuário que define formatação personalizada.

» from string import Formatter
» formatter = Formatter()
» print(formatter.format('Um bom site é {site}', site='Phylos.net.'))
↳ 'Um bom site é Phylos.net.'

# variáveis podem ser posicionais e nomeadas
» print(formatter.format('{} {site}', 'Visite nosso site: ', site='Phylos.net.'))
↳ 'Visite nosso site: Phylos.net.'

# O método de string "format()" tem o mesmo comportamento
» print('{} {site}'.format('Leia sobre vários tópicos em ', site='Phylos.net.'))
↳ 'Leia sobre vários tópicos em Phylos.net.'

Método Template: A outra classe de Formatter é Template, útil para a produção de aplicativos internacionalizados, onde um marcador informa a posição onde texto posterir será inserido.

» from string import Template
» temp = Template('Em $lingua a palavra "$palavra" é traduzida como  "$traducao".')
» texto = temp.substitute(lingua='português', palavra='intruder', traducao='intruso')
» print(texto)
↳ 'Em português a palavra "intruder" é traduzida como  "intruso".'

Bibliografia

Todas as URLs foram visitadas em janeiro de 2024.