logo

Ponteiro em Python | Por que Python não suporta ponteiro

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 -

Ponteiro em Python

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.

Ponteiro em Python

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.

  1. Crie um PyObject
  2. Defina o typecode como inteiro para o PyObject
  3. Defina o valor como 289 para o PyObject
  4. Crie um nome chamado x
  5. Aponte x para o novo PyObject
  6. Aumente a recontagem do PyObject em 1

Será parecido com o abaixo.

Ponteiro em Python

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.