Neste tutorial, aprenderemos sobre ponteiro em Python e veremos por que Python não oferece suporte a conceitos de ponteiro.
Também entenderemos como podemos simular o ponteiro em Python. Abaixo está a introdução do ponteiro para quem não tem nada sobre ele.
Também entenderemos como podemos simular o ponteiro em Python. Abaixo está a introdução do ponteiro para quem não sabe nada sobre ele.
O que é ponteiro?
Ponteiro é uma ferramenta muito popular e útil para armazenar o endereço da variável. Se alguém já trabalhou com uma linguagem de baixo nível como C . C++ , ele/ela provavelmente estaria familiarizado com ponteiros. Ele gerencia o código com muita eficiência. Pode ser um pouco difícil para iniciantes, mas é um dos conceitos importantes do programa. No entanto, isso pode levar a vários bugs de gerenciamento de memória. Assim, a definição de ponteiros -
'Ponteiros são as variáveis que contêm o endereço de memória de outra variável. Variáveis de ponteiro são representadas por asterisco (*).'
Vejamos o seguinte exemplo de ponteiro na linguagem de programação C.
Exemplo - Como usar ponteiro em C
#include int main() { int* po, o; 0 = 10; printf('Address of c: %p ', &c); printf('Value of c: %d ', c); o = &0; printf('Address of pointer pc: %p ', o); printf('Content of pointer pc: %d ', *o); 0 = 11; printf('Address of pointer pc: %p ', p0); printf('Content of pointer pc: %d ', *p0); *po = 2; printf('Address of c: %p ', &o); printf('Value of c: %d ', o); return 0; }
Saída:
Address of o: 2686784 Value of o: 22 Address of pointer po: 2686784 Content of pointer po: 22 Address of pointer po: 2686784 Content of pointer po: 11 Address of o: 2686784 Value of o: 2
Além de serem úteis, os ponteiros não são usados em Pitão . Neste tópico, discutiremos o modelo de objeto do Python e aprenderemos por que não existem ponteiros em Python. Também aprenderemos diferentes maneiras de simular ponteiros em Python. Primeiro, vamos discutir por que Python não oferece suporte a ponteiros.
Por que o Python não suporta ponteiros
A razão exata para não apoiar o ponteiro não está clara. O ponteiro em Python poderia existir nativamente? O conceito principal do Python é a sua simplicidade, mas o ponteiro violou o Zen de Python. Os ponteiros são principalmente mudanças implícitas encorajadas, em vez de mudanças explícitas. Eles também são complexos, principalmente para iniciantes.
Os ponteiros tendem a criar complexidade no código, onde o Python se concentra principalmente na usabilidade e não na velocidade. Como resultado, Python não oferece suporte a ponteiro. No entanto, Python oferece alguns benefícios no uso do ponteiro.
Antes de entender o ponteiro em Python, precisamos ter uma ideia básica dos seguintes pontos.
- Objetos imutáveis vs. objetos mutáveis
- Variáveis/nomes Python
Objetos em Python
Em Python, tudo é um objeto, até mesmo classes, funções, variáveis, etc. Cada objeto contém pelo menos três dados.
repositório maven
- Contagem de referência
- Tipo
- Valor
Vamos discutir um por um.
Contagem de Referência - É usado para gerenciamento de memória. Para obter mais informações sobre o gerenciamento de memória Python, leia Gerenciamento de memória em Python.
Tipo - O CPython camada é usada como o tipo para garantir a segurança do tipo durante o tempo de execução. Finalmente, existe um valor, que é o valor real associado ao objeto.
Se nos aprofundarmos neste objeto, descobriremos que nem todos os objetos são iguais. A distinção importante entre os tipos de objeto é imutável e mutável. Antes de mais nada, precisamos entender a diferença entre os tipos de objeto porque explora o ponteiro em Python.
Objetos imutáveis vs. objetos mutáveis
Objetos imutáveis não podem ser modificados, enquanto objetos mutáveis podem ser modificados. Vamos ver a seguinte tabela de tipos comuns e se eles são mutáveis ou não.
loop aprimorado em java
Objetos | Tipo |
---|---|
Interno | Imutável |
Flutuador | Imutável |
Bool | Imutável |
Lista | Mutável |
Definir | Mutável |
Complexo | Mutável |
Tupla | Imutável |
Conjunto congelado | Imutável |
Ditado | Mutável |
Podemos verificar o tipo dos objetos acima usando o eu ia() método. Este método retorna o endereço de memória do objeto.
Estamos digitando as linhas abaixo em um ambiente REPL.
x = 5 id(x)
Saída:
140720979625920
No código acima, atribuímos o valor 10 a x. se modificássemos este valor com substituição, obteríamos os novos objetos.
x-=1 id(x)
Saída:
140720979625888
Como podemos ver, modificamos o código acima e obtemos novos objetos como resposta. Tomemos outro exemplo de str .
s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s)
Saída:
2315970974512 JavaTpoint 1977728175088
Novamente, modificamos o valor de x adicionando uma nova string e obtemos o novo endereço de memória. Vamos tentar adicionar string diretamente em s.
s = 'java' s[0] = T print(id(s))
Saída:
Traceback (most recent call last): File 'C:/Users/DEVANSH SHARMA/PycharmProjects/MyPythonProject/python1.py', line 34, in s[0] = T NameError: name 'T' is not defined
O código acima retorna erro, significa que a string não suporta a mutação. Então str são os objetos imutáveis.
Agora, veremos o objeto mutável como lista.
my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list))
Saída:
2571132658944 [3, 4, 8, 4] 2571132658944
Como podemos ver no código acima, o minha lista tem o id originalmente e acrescentamos 5 à lista; minha lista tem o mesmo ID porque a lista suporta o mutabilidade.
Compreendendo as variáveis Python
A forma de definir variáveis em Python é muito diferente do C ou C++. A variável Python não define o tipo de dados. Na verdade, Python tem nomes, não variáveis.
Portanto, precisamos entender a diferença entre variáveis e nomes e isso é especialmente verdadeiro quando estamos navegando no assunto complicado de ponteiros em Python.
Vamos entender como funciona a variável em C e como funciona o nome em Python.
Variáveis em C
Na linguagem C, uma variável é aquela que contém valor ou armazena valor. É definido com o tipo de dados. Vamos ver o seguinte código que define a variável.
int x = 286;
- Aloque memória suficiente para um número inteiro.
- Atribuímos o valor 286 a esse local de memória.
- O x representa esse valor.
Se representarmos a visão da memória -
Como podemos ver, x possui um local de memória para o valor 286. Agora, atribuiremos o novo valor a x.
multithreading java
x = 250
Este novo valor substitui o valor anterior. Isso significa que a variável x é mutável.
A localização do valor de x é a mesma, mas o valor mudou. É um ponto significativo indicar que x é a localização da memória, e não apenas o seu nome.
Agora, introduzimos a nova variável que recebe x, então y cria a nova caixa de memória.
int y = x;
A variável y cria uma nova caixa chamada y copia o valor de x para a caixa.
Nomes em Python
Como discutimos anteriormente, Python não possui variáveis. Tem nomes e usamos esse termo como variáveis. Mas há uma diferença entre variáveis e nomes. Vejamos o exemplo a seguir.
x = 289
O código acima é dividido durante a execução.
- Crie um PyObject
- Defina o typecode como inteiro para o PyObject
- Defina o valor como 289 para o PyObject
- Crie um nome chamado x
- Aponte x para o novo PyObject
- Aumente a recontagem do PyObject em 1
Será parecido com o abaixo.
Podemos entender o funcionamento interno de uma variável em Python. A variável x aponta para a referência do objeto e não possui espaço de memória como antes. Também mostra que x = 289 está vinculando o nome x a uma referência.
Agora, introduzimos uma nova variável e atribuímos x a ela.
y = x
Em Python, a variável y não criará o novo objeto; é apenas um novo nome apontando para o mesmo objeto. O objeto recontagem também aumentou em um. Podemos confirmá-lo da seguinte forma.
y is x
Saída:
True
Se aumentarmos o valor de y em um, ele não se referirá mais ao mesmo objeto.
y + =1 y is x
Isso significa que em Python não atribuímos variáveis. Em vez disso, vinculamos nomes a referências.
Simulando ponteiros em Python
Como discutimos, Python não oferece suporte a ponteiros, mas podemos obter os benefícios de usar um ponteiro. Python fornece maneiras alternativas de usar o ponteiro em Python. Essas duas maneiras são fornecidas abaixo.
- Usando tipos mutáveis como ponteiros
- Usando objetos Python personalizados
Vamos entender os pontos dados.
Usando tipos mutáveis como ponteiro
Na seção anterior, definimos os objetos de tipo mutável; podemos tratá-los como se fossem ponteiros para simular o comportamento do ponteiro. Vamos entender o exemplo a seguir.
C
void add_one(int *a) { *a += 1; }
No código acima, definimos o ponteiro *a, então incrementamos o valor em um. Agora, vamos implementá-lo com a função main().
o que é 25 de 100
#include int main(void) { int y = 233; printf('y = %d ', y); add_one(&y); printf('y = %d ', y); return 0; }
Saída:
y = 233 y = 234
Podemos simular esse tipo de comportamento usando o tipo mutável Python. Entenda o exemplo a seguir.
def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0]
A função acima acessa o primeiro elemento da lista e incrementa seu valor em um. Quando executamos o programa acima, ele imprime o valor modificado de y. Isso significa que podemos replicar o ponteiro usando o objeto mutável. Mas se tentarmos simular um ponteiro usando um objeto imutável.
z = (2337,) add_one(z)
Saída:
Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment
Usamos a tupla no código acima, um objeto imutável, então ela retornou o erro. Também podemos usar o dicionário para simular o ponteiro em Python.
Vamos entender o exemplo a seguir onde contaremos todas as operações que ocorrem no programa. Podemos usar dict para conseguir isso.
Exemplo -
count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls']
Saída:
2
Explicação -
No exemplo acima, usamos o contar dicionário, que monitorava o número de chamadas de função. Quando o foo() a função é chamada, o contador é aumentado em 2 porque dict é mutável.
Usando objetos Python
No exemplo anterior, usamos dict para emular o ponteiro em Python, mas às vezes fica difícil lembrar todos os nomes de chaves usados. Podemos usar a classe personalizada Python no lugar do dicionário. Vamos entender o exemplo a seguir.
Exemplo -
class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, }
No código acima, definimos a classe Pointer. Esta classe usou dict para armazenar dados reais na variável de membro _metrics. Isso fornecerá mutabilidade ao nosso programa. Podemos fazer isso da seguinte maneira.
class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served']
Nós usamos @propriedade decorador. Se você não está familiarizado com decoradores, visite nosso tutorial sobre decoradores Python. O decorador @property acessará funCalls e catPicture_served. Agora, criaremos um objeto da classe Pointer.
pt = Pointer() pt.funCalls() pt.catPicture_served
Aqui precisamos incrementar esses valores.
class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1
Definimos dois novos métodos - increment() e cat_pics(). Modificamos os valores usando essas funções no ditado de matrizes. Aqui, podemos alterar a classe da mesma forma que modificamos o ponteiro.
pt = Pointer() pt.increment() pt.increment() pt.funCalls()
Módulo ctypes Python
O módulo Python ctypes nos permite criar um ponteiro do tipo C em Python. Este módulo é útil se quisermos fazer uma chamada de função para uma biblioteca C que requer um ponteiro. Vamos entender o exemplo a seguir.
Exemplo - Linguagem C
void incr_one(int *x) { *x += 1; }
Na função acima, aumentamos o valor de x em um. Suponha que salvemos o arquivo acima chamado incrPointer.c e digite o seguinte comando no terminal.
$ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o
O primeiro comando compila incrPointer.c em um objeto chamado incrPointer.o. O segundo comando aceita arquivo objeto e produz libinic.so para colaborar com ctypes.
np zeros
import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment
Saída:
No código acima, o ctypes.CDLL retorna um objeto compartilhado chamado libínico.so. Ele contém o ponteiro incr() função. Se precisarmos especificar o ponteiro para as funções que definimos em um objeto compartilhado, teremos que especificá-lo usando ctypes. Vejamos o exemplo abaixo.
inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)]
Se chamarmos a função usando um tipo diferente, ocorrerá um erro.
incrPointer(10)
Saída:
Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int
Isso ocorre porque incrPointer requer um ponteiro e ctypes é uma forma de passar ponteiro em Python.
v = ctypes.c_int(10)
v é uma variável C. O ctypes fornece o método chamado byref() que costumava passar a referência da variável.
inc(ctypes.byref(a)) a
Saída:
c_int(11)
Aumentamos o valor usando a variável de referência.
Conclusão
Discutimos que o ponteiro não está presente no Python, mas podemos implementar o mesmo comportamento com o objeto *mutável. Também discutimos os módulos ctypes que podem definir o ponteiro C em Python. Definimos algumas maneiras excelentes de simular ponteiros em Python.