Python小ネタ


目次

  1. バイトオーダー変換
  2. IPアドレス変換(整数値↔︎文字列)
    1. IPv4の場合
    2. IPv6の場合
  3. MACアドレス変換(整数値↔︎文字列)
  4. シグナルハンドラ


1.バイトオーダー変換

Cのhtonl()ライクな処理がしたかったのです。
そこは流石pythonですね。
標準でバイトオーダー変換ができるモジュールが用意されていました。

バイトオーダ変換の方法はいくつか見つかったのですが、
その中でも、int→bytes→intで変換する方法が一番簡単かと思いました。

以下は1を32bitでバイトオーダ変換(16777216になる)する例です。

x = 1
y = int.from_bytes(x.to_bytes(4, byteorder=sys.byteorder), byteorder='big') 

※バイナリ的にはb’\x01\x00\x00\x00’→b’\x00\x00\x00\x01’の変換

ざっくり解説すると以下の感じでしょうか。
int.from_bytes(<変換元の整数>.to_bytes(<変換するbyteの長さ>, byteorder=<変換元のバイトオーダー>), byteorder=<変換したいバイトオーダー>)

ポイントとしては変換するバイト長を間違えないことです。
例えば、IPv4のアドレスの変換を行いたいのであれば、
4(32bit)を指定しないといけません。
(IPアドレスの変換であればipaddress型を使うべきですが)

また、to_bytesで指定するbyteorderにはsys.byteorderを使用するのが無難でしょう。
sys.byteorderでは、自分が使用しているシステムのバイトオーダーを取得できます。

参考↓
https://docs.python.org/ja/3/library/stdtypes.html#additional-methods-on-integer-types


2.IPアドレス変換(整数値↔︎文字列)

先ほどチラッと触れましたが、IPアドレスの変換であればipaddress型を使うののがベストプラクティスです。
(ipaddress型は高機能な反面、若干遅いと言う問題点もあるので性能が要求される場合は自前でゴリゴリ書きましょう。というか性能重視ならCで…)


2-A IPv4の場合

・整数値→文字列
※以下は0→’0.0.0.0’の変換の例

ipv4_str = str(ipaddress.ip_address(0))

ポイントは、バイトオーダーはシステム(普通はビッグエンディアン)になる点です。
つまり、ネットワークから取得したIPアドレス等を変換したい場合は、バイトオーダーを変換する必要があります。


・文字列→整数値
※以下は’0.0.0.0’→0の変換の例

ipv4_int = int(ipaddress.ip_address('0.0.0.0'))

こちらも先ほどと同じでバイトオーダーはシステム(普通はビッグエンディアン)になるので注意です。

参考
https://docs.python.org/ja/3/library/ipaddress.html?highlight=ipaddress#conversion-to-strings-and-integers


2-B IPv6の場合

・整数値→文字列

str(ipaddress.IPv6Address(1))

IPv4と異なり、明示的にIPv6型を使用する必要があります。
なぜなら、ipaddress型は::1のような32bitにおさまる値を無条件でIPv4として扱ってしまうからです。

・文字列→整数値

IPv4と同じ方法で問題ないです。

※IPv6の場合128bitの整数値の扱いも問題になったりしますが、その辺はstruct等を駆使して頑張りましょう。


3.MACアドレス変換

・整数値→文字列
※1234→’00-00-00-00-04-d2’の例

import struct

"-".join([format(i, 'x').zfill(2) for i in struct.pack("!Q", 1234)[2:]])

やってることとしてはbytes型に変換してイテレータ回して1byteずつ変換しているだけです。
structに6byteに対応するものがないので末尾に[2:]がついてます。

※formatの部分の’x’を大文字にすると16進数のアルファベットの部分を大文字にできます。


・文字列→整数値(需要なさそう)
※’00-00-00-00-04-d2’→1234の例

int(bytearray(int(i, 16) for i in '00-00-00-00-04-d2'.split("-")).hex(), 16)

“-“で分割→1byteずつintに変換→bytearrayにぶちこむ→16進数文字列に変換→intに変換

…ゴリ押し感がすごいですが、変換は正しいです。


4.シグナルハンドラ

シグナルを受信した時の動作を設定できるハンドラがシグナルハンドラです。
Ctrl+CでSIGINTが飛んできた時に独自の終了処理を実行できたりします。

pythonでシグナルハンドラを設定するのは簡単で、たった2ステップでできてしまいます。
①シグナルを受信した時に実行したい関数を用意する
②受信したいシグナルを設定する


ベリーイージーですね。
それではサンプルコードどうぞ。


とても簡単ですが、注意点もあるので以下は気をつけてください。

  • シグナルハンドラに設定する関数は(signum, frame)という二つの引数を必ずとる
  • signal.signal()で設定しなかったシグナルに対してはデフォルトの動作が適用される(例えばSIGINTだけをハンドラに設定していた場合SIGTERMを受信したらハンドラが呼ばれずに殺されるということです。)
  • シグナルはプロセス全体に送信されるのでスレッド間の通信には使えない


詳しくは以下の公式ドキュメントとか、OS仕様で確認してください。
https://docs.python.org/ja/3/library/signal.html


参考

https://docs.python.org/ja/3/library/stdtypes.html#built-in-types
https://docs.python.org/ja/3/library/ipaddress.html?highlight=ipaddress#module-ipaddress
https://qiita.com/FmtWeisszwerg/items/c7aa26859c463dda5ebc

Leave a Reply

Your email address will not be published. Required fields are marked *