logo

Python のポインター | Python がポインタをサポートしない理由

このチュートリアルでは、Python のポインターについて学び、Python がポインターの概念をサポートしない理由を説明します。

また、Python でポインターをシミュレートする方法についても理解します。以下に、何も知らない人のために注意点を紹介します。

また、Python でポインターをシミュレートする方法についても理解します。以下に、何も知らない人のために注意事項を紹介します。

ポインタとは何ですか?

ポインターは、変数のアドレスを保存するための非常に人気のある便利なツールです。誰かがこれまでに次のような低レベル言語を使用したことがある場合 CC++ 、彼/彼女はおそらくポインターに精通しているでしょう。コードを非常に効率的に管理します。初心者には少し難しいかもしれませんが、プログラムの重要な概念の 1 つです。ただし、さまざまなメモリ管理のバグが発生する可能性があります。したがって、ポインタの定義は -

ポインタは、別の変数のメモリ アドレスを保持する変数です。ポインタ変数はアスタリスク (*) で表されます。

C プログラミング言語でのポインターの次の例を見てみましょう。

例 - 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; } 

出力:

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 

ポインタは便利であるだけでなく、 パイソン 。このトピックでは、Python のオブジェクト モデルについて説明し、Python にポインターが存在しない理由を学びます。また、Python でポインターをシミュレートするさまざまな方法も学習します。まず、Python がポインターをサポートしない理由について説明します。

Python がポインターをサポートしない理由

ポインターをサポートしない正確な理由は不明です。 Python のポインタはネイティブに存在する可能性がありますか? Python の主な概念はその単純さですが、ポインタはその概念に違反していました。 Pythonの禅。 ポインターは、明示的な変更ではなく、主に暗黙的な変更を推奨します。また、特に初心者にとっては複雑です。

ポインターはコードに複雑さをもたらす傾向があり、Python では主に速度よりも使いやすさに焦点を当てています。結果として、Python はポインターをサポートしません。ただし、Python にはポインターを使用する利点がいくつかあります。

Python のポインターを理解する前に、次の点について基本的な考え方を理解する必要があります。

  • 不変オブジェクトと可変オブジェクト
  • Python の変数/名前

Python のオブジェクト

Python では、クラス、関数、変数なども含めてすべてがオブジェクトです。各オブジェクトには少なくとも 3 つのデータが含まれています。

Javaユーザー入力
  • 参照カウント
  • タイプ
  • 価値

一つずつ話し合いましょう。

参照カウント - メモリ管理に使用されます。 Python のメモリ管理の詳細については、「Python のメモリ管理」を参照してください。

タイプ -CPython レイヤーは、実行時の型の安全性を確保するために型として使用されます。最後に、オブジェクトに関連付けられた実際の値である値があります。

ただし、このオブジェクトを詳しく調べてみると、すべてのオブジェクトが同じではないことがわかります。オブジェクトのタイプの重要な違いは、不変と可変です。まず第一に、Python ではポインターを探索するため、オブジェクトのタイプの違いを理解する必要があります。

不変オブジェクトと可変オブジェクト

不変オブジェクトは変更できませんが、可変オブジェクトは変更できます。次の表で一般的な型と、それらが変更可能かどうかを見てみましょう。

int 文字列 Java
オブジェクト タイプ
内部 不変
浮く 不変
ブール 不変
リスト 可変
セット 可変
複雑な 可変
タプル 不変
フローズンセット 不変
辞書 可変

上記のオブジェクトのタイプを確認するには、 id() 方法。このメソッドはオブジェクトのメモリ アドレスを返します。

REPL 環境で以下の行を入力しています。

 x = 5 id(x) 

出力:

140720979625920 

上記のコードでは、x に値 10 を割り当てています。この値を置換で変更すると、新しいオブジェクトが取得されます。

 x-=1 id(x) 

出力:

140720979625888 

ご覧のとおり、上記のコードを変更し、応答として新しいオブジェクトを取得します。別の例を挙げてみましょう str

 s = 'java' print(id(s)) s += 'Tpoint' print(s) id(s) 

出力:

2315970974512 JavaTpoint 1977728175088 

ここでも、新しい文字列を追加して x の値を変更し、新しいメモリ アドレスを取得します。 s に文字列を直接追加してみましょう。

 s = 'java' s[0] = T print(id(s)) 

出力:

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 

上記のコードはエラーを返します。これは、文字列が突然変異をサポートしていないことを意味します。それで str は不変オブジェクトです。

次に、リストなどの可変オブジェクトを見てみましょう。

 my_list = [3, 4, 8] print(id(my_list)) my_list.append(4) print(my_list) print(id(my_list)) 

出力:

2571132658944 [3, 4, 8, 4] 2571132658944 

上記のコードからわかるように、 私のリスト 元々 ID があり、リストに 5 を追加しました。 私のリスト リストがサポートしているため、同じ ID を持ちます。 可変性。

Python 変数を理解する

Python で変数を定義する方法は、C や C++ とは大きく異なります。 Python 変数はデータ型を定義しません。実際、Python には変数ではなく名前があります。

したがって、変数と名前の違いを理解する必要があり、Python でポインターという難しい主題を扱う場合には特にそうです。

C で変数がどのように機能するか、そして Python で名前がどのように機能するかを理解しましょう。

C の変数

C言語では、変数とは、値を保持する、または値を格納するものです。データ型で定義されます。変数を定義する次のコードを見てみましょう。

 int x = 286; 
  • 整数に十分なメモリを割り当てます。
  • そのメモリ位置に値 286 を割り当てます。
  • x はその値を表します。

記憶の見方を表現すると -

Python のポインター

ご覧のとおり、x には値 286 のメモリ位置があります。次に、新しい値を x に割り当てます。

x = 250

この新しい値は以前の値を上書きします。これは、変数 x が可変であることを意味します。

x の値の位置は同じですが、値が変更されています。これは、x が単なる名前ではなくメモリの場所であることを示す重要な点です。

ここで、x を受け取る新しい変数を導入し、y で新しいメモリ ボックスを作成します。

 int y = x; 

変数 y は y という新しいボックスを作成し、x の値をボックスにコピーします。

Python のポインター

Python での名前

前に説明したように、Python には変数がありません。名前があり、この用語を変数として使用します。ただし、変数と名前には違いがあります。次の例を見てみましょう。

 x = 289 

上記のコードは実行中に分解されます。

  1. PyObject を作成する
  2. PyObject のタイプコードを整数に設定します。
  3. PyObject の値を 289 に設定します。
  4. x という名前を作成します
  5. x を新しい PyObject にポイントします
  6. PyObject の refcount を 1 増やします

以下のようになります。

Python のポインター

Python の変数の内部動作を理解できます。変数 x はオブジェクトの参照を指しており、以前のようなメモリ空間はありません。また、x = 289 が名前 x を参照にバインドしていることも示しています。

ここで、新しい変数を導入し、それに x を代入します。

 y = x 

Python では、変数 y は新しいオブジェクトを作成しません。これは、同じオブジェクトを指す新しい名前にすぎません。オブジェクト 参照カウント も1つ増えました。以下のように確認できます。

 y is x 

出力:

True 

y の値を 1 つ増やすと、同じオブジェクトを参照しなくなります。

 y + =1 y is x 

つまり、Python では変数を割り当てません。代わりに、名前を参照にバインドします。

データベース

Python でのポインターのシミュレーション

すでに説明したように、Python はポインターをサポートしていませんが、ポインターを使用することで利点が得られます。 Python では、Python でポインターを使用する別の方法が提供されています。これら 2 つの方法を以下に示します。

  • 可変型をポインターとして使用する
  • カスタム Python オブジェクトの使用

与えられたポイントを理解しましょう。

可変型をポインターとして使用する

前のセクションでは、可変型オブジェクトを定義しました。ポインタの動作をシミュレートするために、それらをポインタであるかのように扱うことができます。次の例を理解してみましょう。

C

 void add_one(int *a) { *a += 1; } 

上記のコードでは、ポインター *a を定義し、値を 1 ずつインクリメントします。次に、main() 関数を使用して実装します。

最初のラップトップ
 #include int main(void) { int y = 233; printf('y = %d
', y); add_one(&y); printf('y = %d
', y); return 0; } 

出力:

y = 233 y = 234 

Python の可変型を使用して、このタイプの動作をシミュレートできます。次の例を理解してください。

 def add_one(x): x[0] += 1 y = [2337] add_one(y) y[0] 

上記の関数は、リストの最初の要素にアクセスし、その値を 1 つ増やします。上記のプログラムを実行すると、変更された y の値が出力されます。これは、可変オブジェクトを使用してポインターを複製できることを意味します。しかし、不変オブジェクトを使用してポインタをシミュレートしようとすると、

 z = (2337,) add_one(z) 

出力:

Traceback (most recent call last): File '', line 1, in File '', line 2, in add_one TypeError: 'tuple' object does not support item assignment 

上記のコードでは不変オブジェクトであるタプルを使用しているため、エラーが返されました。辞書を使用して、Python でポインターをシミュレートすることもできます。

プログラム内で発生するすべての操作をカウントする次の例を理解しましょう。これを実現するには dict を使用できます。

例 -

 count = {'funcCalls': 0} def car(): count['funcCalls'] += 1 def foo(): count['funCcalls'] += 1 car() foo() count['funcCalls'] 

出力:

2 

説明 -

上の例では、 カウント 関数呼び出しの数を追跡する辞書。とき foo() 関数が呼び出されると、dict は可変であるため、カウンターが 2 増加します。

Python オブジェクトの使用

前の例では、dict を使用して Python でポインターをエミュレートしましたが、使用されたすべてのキー名を覚えておくのが困難になる場合があります。辞書の代わりに Python カスタム クラスを使用できます。次の例を理解してみましょう。

例 -

 class Pointer(object): def __init__(self): self._metrics = { 'funCalls': 0, 'catPictures': 0, } 

上記のコードでは、Pointer クラスを定義しました。このクラスは、実際のデータを _metrics メンバー変数に保持するために dict を使用しました。それはプログラムに可変性を提供します。これは次のようにして実行できます。

 class Pointer(object): # ... @property def funCalls(self): return self._metrics['func_calls'] @property def catPictures_served(self): return self._metrics['cat_pictures_served'] 

私たちが使用したのは @財産 デコレーター。デコレータに詳しくない場合は、Python デコレータ チュートリアルを参照してください。 @property デコレータは funCalls と catPicture_served にアクセスします。次に、Pointer クラスのオブジェクトを作成します。

 pt = Pointer() pt.funCalls() pt.catPicture_served 

ここで、これらの値をインクリメントする必要があります。

 class Pointer(object): # ... def increament(self): self._metrices['funCalls'] += 1 def cat_pics(self): self._metrices['catPictures_served'] += 1 

2 つの新しいメソッド、increment() と cat_pics() を定義しました。行列 dict でこれらの関数を使用して値を変更しました。ここでは、ポインターを変更するのと同じようにクラスを変更できます。

 pt = Pointer() pt.increment() pt.increment() pt.funCalls() 

Python ctypes モジュール

Python ctypes モジュールを使用すると、Python で C 型ポインターを作成できます。このモジュールは、ポインターを必要とする C ライブラリへの関数呼び出しを行う場合に役立ちます。次の例を理解してみましょう。

例 - C 言語

 void incr_one(int *x) { *x += 1; } 

上記の関数では、x の値を 1 ずつ増加させました。上記のファイルを incrPointer.c という名前で保存し、ターミナルに次のコマンドを入力するとします。

 $ gcc -c -Wall -Werror -fpic incrPointer.c $ gcc -shared -o libinc.so incrPointer.o 

最初のコマンドはコンパイルされます incrPointer.c というオブジェクトに incrPointer.o. 2 番目のコマンドはオブジェクト ファイルを受け入れ、ctypes と連携するための libonic.so を生成します。

フィボナッチ数列Java
 import ctypes ## libinc.so library should be same directory as this program lib = ctypes.CDLL('./libinc.so') lib.increment 

出力:

 

上記のコードでは、 ctypes.CDLL という共有オブジェクトを返します libinic.so。 含まれているのは、 incrPointer() 関数。共有オブジェクトで定義する関数へのポインターを指定する必要がある場合は、ctypes を使用して指定する必要があります。以下の例を見てみましょう。

 inc = lib.increment ## defining the argtypes inc.argtypes = [ctypes.POINTER(ctypes.c_int)] 

別の型を使用して関数を呼び出すと、エラーが発生します。

 incrPointer(10) 

出力:

Traceback (most recent call last): File '', line 1, in ctypes.ArgumentError: argument 1: : expected LP_c_int instance instead of int 

これは、incrPointer にはポインターが必要であり、ctypes は Python でポインターを渡す方法であるためです。

 v = ctypes.c_int(10) 

v は C 変数です。 ctypes は、と呼ばれるメソッドを提供します。 byref() これは変数参照を渡すために使用されていました。

 inc(ctypes.byref(a)) a 

出力:

c_int(11) 

参照変数を使用して値を増やしました。

結論

Python にはポインターが存在しないことについて説明しましたが、*mutable オブジェクトを使用して同じ動作を実装できます。 Python で C ポインターを定義できる ctypes モジュールについても説明しました。 Python でポインターをシミュレートする優れた方法をいくつか定義しました。