0
1

python

Last updated at Posted at 2024-03-21

Python

参考

用語など

  • イテレータ
  • ジェレネータ
  • コルーチン
  • 並列化
    • マルチスレッド
    • マルチプロセス
  • 非同期処理
    • コールバック
    • Promise
    • async/awaite

まとめ

イテレータ・イテラブル

  • イテラブル(iterable)
    for 文で繰り返し処理ができるクラスのこと。
    実装としては、__iter__() or __getitem__() を実装しているクラス。
    • __iter__() はイテレータを意識したクラス

    • __getitem__() はリスト等を意識したクラス
       

      lists = [1, 2, 3]
      for l in lists:
          print(l)
      
      # 書き換えると以下のように処理されている
      ite = [1, 2, 3].__iter__() # ite = iter([1, 2, 3])
      while True:
          try:
              l = ite.__next__() # l = next(ite)
          except StopIteration:
              break
          print(l)
      
      class Sequence:
          def __getitem__(self, index):
              if 0 <= index <= 3:
                  return index * 2
              else:
                  raise IndexError
      
      seq = Sequence()
      print(seq[0])
      print(seq[1])
      print(seq[2])
      print(seq[3])
      
      for i in seq:
          print(i)
      

 

  • イテレータ(iterator)
    実装としては、__iter__() or __next__() を実装しているクラス。
    イテラブルであるため、for文でも使用できる。また、iter(), next() を使ってイテレーションできる。

    class Counter:
        def __init__(self, start, stop):
            self._counter = start
            self._stop = stop
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self._counter > self._stop:
                raise StopIteration()
            ret = self._counter
            self._counter += 1
            return ret
    
    c = Counter(start=1, stop=3)
    c = iter(c)
    print(next(c)) # 1
    print(next(c)) # 2
    print(next(c)) # 3
    print(next(c)) # StopIteration
    
    c = Counter(start=1, stop=3)
    for i in c:
        print(i)
    

ジェネレータ

  • ジェネレータ
    関数定義で、yield 式を使うことで定義される。
    通常の関数定義内で yield を使った場合は ジェネレータ関数 となり、
    async def 関数定義内で使った場合は コルーチン関数(非同期ジェネレータ関数) となる。
    Python 言語リファレンス Yield 式

    ※通常の関数と異なり、ジェネレータ関数がコールされた場合、
    すぐに関数内が実行されるわけではなく、ジェネレータイテレータオブジェクトを返す。
    その後にジェネレータメソッド(generator.next() or generator.send())がコールされて初めて関数が実行されることに注意。

    • next(generator) = generator.send(None) と考えていい?
    def main():
        a = simple()        # 実行されずジェネレータを返すだけ
        print('first')
        x = a.send(None)    # ここで初めてジェネレータが(yieldまで)実行される
        print(x)            # third
        y = a.send('forth')
        print(y)            # fifth
    
    def simple():
        print('second')
        s = yield 'third'
        print(s)
        yield 'fifth'
    
    main()
    # first
    # second
    # third
    # forth
    # fifth
    
    def echo(value=None):
        print("最初に 'next()' がコールされたときに実行が始まる.")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    value = e
        finally:
            print("'close()' がコールされたときにクリーンアップを忘れないように")
    
    generator = echo(1)      # ジェネレータイテレータオブジェクトを返すだけ
    print(next(generator))   # 最初に 'next()' がコールされたときに実行が始まる. 
                             # 1
    print(next(generator))   # None
    print(generator.send(2)) # 2
    generator.throw(TypeError, "spam") # TypeError("spam")
    generator.close() # 'close()' がコールされたときにクリーンアップを忘れないように
    
  • yield from

    from のあとにイテラブルを指定する。
    基本は、yield from iterable = for item in iterable: yield item

    def g():
        for c in 'AB':
            yield c
        for i in range(1, 3):
            yield i
    print( list(g()) )  # ['A', 'B', 1, 2]
    
    def g2():
        yield from 'AB' 
        yield from range(1, 3)
    

    本来の目的は、「一番外側の呼び出し側」と「一番内側のジェネレータ」間で値の送受信や例外処理できるようにすること。

      def delegator():
          while True:
              res = yield from subgenerator()
              print(res)
    
      def subgenerator():
          while True:
              recv = yield
              if recv is None:
                  break
              print(recv)
          return 'fin.'
    
      g = delegator()  # ジェネレータイテレータオブジェクトを返すだけ
      next(g)
      g.send('A')      # A
      g.send('B')      # B
      g.send(None)     # fin.
    

with

処理を終了する際に、必ず実行すべき処理があることが多い。
その場合、with を使って記述すると自動的に終了処理を行ってくれるようになる。
実装としては、__enter__() or __exit__() を実装しているクラス。

class WithClass:
    @classmethod
    def create(cls):
        return WithClass()

    def __init__(self):
        print("init")

    def hoge(self):
        print("hoge")

    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, ex_type, ex_value, trace):
        print(f"exit: {ex_type} {ex_value} {trace}")
        # return True # 例外を無視することできる

with WithClass() as w:   # クラスのインスタンス化+処理開始
    w.hoge()             # 処理
                         # with を抜けた処理
# init
# enter
# hoge
# exit: None None None

# 同じ動作をする
with WithClass.create() as w:
    w.hoge()

# 以下と等価
manager = WithClass()
enter   = type(manager).__enter__
exit    = type(manager).__exit__
value   = enter(manager)
hit_except = False
try:
    w = value
    w.hoge()
except:
    hit_except = True
    if not exit(manager, *sys.exc_info());
        raise
finally:
    if not hit_except:
        exit(namager, None, None, None)

ソケット通信

A Complete Guide to Socket Programming in Python

  • ソケットは、抽象的なリモート接続管理のインターフェースである。

  • ソケットは、ローカルPC内またはネットワーク越しのPC同士の異なるプロセス間(通常はサーバとクライアント)の情報伝達を可能にする。

  • Pythonでは、ソケットを動作させるにはsocketライブラリを通して実現し、データ送受信のためのメソッドを持つソケットオブジェクトを提供している。

  • ソケットプログラミングはデータサイエンスで役に立つアプリケーションを持つ。

    • Server
    import socket
    
    server_ip   = "127.0.0.1"
    server_port = 8000
    
    def run_server():
        try:
    
            # ソケットのインスタンス化
            # socket.AF_INET : IPv4
            # socket.AF_INET6: IPv6
            # socket.SOCK_STREAM: TCP
            # socket.SOCK_DGRAM : UDP
            # socket.RAW_SOCKET : 低レベルプロトコル
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
            # ソケットをIPアドレスとポートに結び(bind)つける
            server.bind((server_ip, server_port))
    
            # クライアントを待ち受ける
            # backlog: acceptしていない接続をキューにいれる最大数。0 = 1クライアントだけ受け入れる
            #  省略するとOSのデフォルト値が使われる(/proc/sys/net/core/somaxconn)
            server.listen(0)
            print(f"Listening on {server_ip}:{server_port}")
    
            # 接続を受け入れる(クライアントアクセスがあるまで処理が止まる)
            # 通常処理ではaccept() 後はクライアント接続がブロックされるので1クライアントしか処理できない
            # client_socket : 接続したクライアントのソケット
            # client_address: 接続したクライアントのIP情報
            client_socket, client_address = server.accept()
            print(f"Accepted connection from {client_address[0]}:{client_address[1]}")
    
            # 通信処理
            while True:
                # byte で取得される
                request = client_socket.recv(1024)
                request = request.decode("utf-8")
                
                if request.lower() == "close":
                    client_socket.send("closed".encode("utf-8"))
                    break
                
                print(f"Recieve: {request}")
                response = "accepted".encode("utf-8")
                client_socket.send(response)
    
        except Exception as e:
            print("Error occurred: {e}")
        finally:
            # 切断処理。システムリソースを解放する。
            client_socket.close()
            print("Connection to client closed")
    
        # サーバを停止
        server.close()
    
    run_server()
    
    • Client
    import socket
    
    server_ip = "127.0.0.1"
    server_port = 8000
    
    def run_client():
        # ソケットのインスタンス化
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # サーバに接続
        client.connect((server_ip, server_port))
    
        try:
            # 通信処理
            while True:
                # メッセージ入力し、サーバへ送信
                msg = input("Enter message: ")
                client.send(msg.encode("utf-8")[:1024])
                
                response = client.recv(1024)
                response = response.decode("utf-8")
                if response.lower() == "closed":
                    break
                
                print(f"Recieved: {response}")
    
        except Exception as e:
            print("Error occurred: {e}")
        finally:
            client.close()
            print("Connection to server closed")
    
    run_client()
    

並列化

その並列処理待った! 「Python 並列処理」でググったあなたに捧ぐasync, threading, multiprocessingのざっくりとした説明

Pythonをとりまく並行/非同期の話し

並列処理 => 本当に複数の処理を同時に実行する
並行処理 => 複数の処理を効率よく切り替えながらあたかも同時に実行する

async/await

future

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1