def atomic_stdlib_re(self): global _message m = re.match(r'(?=(?P<tmp>\d*:))(?P=tmp)', _message) if m: pr('atomic_stdlib_re', 'マッチした') else: pr('atomic_stdlib_re', 'マッチしない')
def exec(self): #################################################### # iter(callable, sentinel) # # 組み込み関数の iter は、引数が一つの場合と # 二つの場合で挙動が異なる。 # # 引数が一つの場合、要求される引数は iterable だが # 引数が二つの場合、要求される引数は # callable と sentinel # となる。 # # sentinel は、日本語で言うと「番兵」の事。 # iter(callable, sentinel) は、毎回 callable を # 呼び出して、その値が sentinel と等しいかを判定する。 # # 等しい場合は、StopIteration が発生して # イテレーションが終わる。 # # なので、何かの値が出てくるまで継続するという # 処理と記述する時に使える。 #################################################### try: self._write_dummy_file() with open(self._file, mode='r', encoding='utf-8') as f: sentinel = MySentinel() it = iter(f.readline, sentinel) for i, line in enumerate(it): pr(f'line-{i:02}', line) finally: self._delete_dummy_file()
def exec(self): """ contextlib.redirect_stdout についてのサンプルを実行します。 :return: なし """ # ---------------------------------------------------------------------- # contextlib.redirect_stdout(new_target) # # 一時的にsys.stdoutを指定した矛先に向けてくれるコンテキストマネージャ # 兄弟関数として、contextlib.redirect_stderr がある。こちらは sys.stderr用 # ---------------------------------------------------------------------- # 以下のprint関数は結果をprint関数で出力しているので # 通常だと、標準出力に出力されるが redirect_stdout で矛先を変更している f = io.StringIO() with redirect_stdout(f): Sample.tekito() pr('f', f.getvalue()) # 同様に help() は、通常 stdout に結果を出力するが # redirect_stdout することで結果を StringIO に格納 f.seek(io.SEEK_SET) with redirect_stdout(f): help(sum) pr('f', f.getvalue())
def normal(self): global _message m = re.match(r'\d*:', _message) if m: pr('normal', 'マッチした') else: pr('normal', 'マッチしない')
def decorator_function(*args, **kwargs): func_result = func(*args, **kwargs) result = sum(range(1, func_result + 1)) pr('sum_it', result) return result
def exec(self): # # multiprocessingモジュール # threadingと似た構成を持つモジュール。threadingがスレッドを扱うのに # 対して、こちらはプロセスを扱う。Pythonでは、GILの絡みがあって # マルチコアな処理をthreadingで記述することが難しいため # そのような処理を記述する場合は multiprocessing モジュールを利用する # # つまり、CPUバウンドな処理の場合は multiprocessing, IOバウンドな処理は # threadingのような利用用途となる。 # # # multiprocessingモジュールで最も基本的なものが Process. # その名の通り、プロセスを表す。 # c01 = multiprocessing.current_process() p01 = multiprocessing.Process(target=Sample.fn01, args=['hello from another process']) pr('current process', c01.pid) p01.start() # 開始 p01.join() # 終了待機 # # 便利なものとして、Pool がある。 # 指定した数のプロセスを起動してコネクションプールのように扱える # with multiprocessing.Pool(os.cpu_count()) as pl: pr('Pool.map()', pl.map(Sample.fn02, list(range(10))))
def exec(self): # ------------------------------------------------------------ # Assignment Expression (Walrus operator) # # 通称「セイウチ演算子」 := を横から見るとセイウチに似ているのでこの名前がついている # := は、代入と評価を同時に行うことができる. # ------------------------------------------------------------ # Python 3.7 までは以下のように記載していた walrus = False pr('walrus = True', walrus) # Python 3.8 からの Assignment Expression を利用すると以下のように書ける pr('walrus := True', walrus := True) pr('walrus', walrus) # Python 3.7 までは以下のように記載していた num = self._get_random_num() if num < 5: print(f'num < 5 {num}') else: print(f'num >= 5 {num}') # Python 3.8 では以下のように書ける if num := self._get_random_num() < 5: print(f'[walrus] num < 5 {num}')
def exec(self): # ---------------------------------------------------------- # joblib モジュールは、以下の機能を持つライブラリ。 # ・透過的で速いキャッシュ (joblib.Memory) # ・並列処理ヘルパー (joblib.Parallel) # ・pickleの代わりに利用できる永続化 (joblib.dump/load) # ---------------------------------------------------------- start_dt = NOW() # ---------------------------------------------------------- # joblib.Parallelの最も基本的な利用方法 # -------------------------------------- # Parallel関数の引数「n_jobs」には並列稼働させる数を指定する。 # ここで指定された値分のプロセスが起動して並列処理を実施する。 # 値に -1 を指定すると、マシンのCPU数を指定したことと同じになる。 # # Parallelの中で、並列処理したい処理に対して joblib.delayed を # 指定して処理する。delayed関数の引数に実際の処理を実施する関数を # 指定し、返ってくるオブジェクトに対して元々の関数の引数を指定する。 # ---------------------------------------------------------- results = joblib.Parallel(n_jobs=-1)( [ joblib.delayed(heavy_proc)(f'value-{i}', RND.randrange(1, 10)) for i in range(1, 5) ] ) end_dt = NOW() pr('job-results', results) pr('total elapsed', (end_dt - start_dt).seconds)
def exec(self): with timetracer('contextmanager-sample'): # # クラス定義で ContextManager の動きをサポートする場合 # dunderメソッドの __enter__() と __exit__() を実装する # py3.6から、contextlib.AbstractContextManagerクラスが追加された # ので、このクラスを基底クラスにして、オーバーライドするとラク # with HasCtxManager() as o: pr('inside-with', o) with HasCtxManager() as o: pr('inside-with', o) raise CtxTestException('this is test ex') # # 関数定義で、ContextManager の動きをサポートする場合 # @contextlib.contextmanager デコレートを使用する # その上で、関数内で yield する必要がある # with return_none_ctx_manager() as o: pr('inside-with', o) with return_none_ctx_manager() as o: pr('inside-with', o) raise CtxTestException('this is test ex2') with return_obj_ctx_manager() as o: # type: SayHelloWorld pr('inside-with', o) o.say()
def exec(self): # ---------------------------------------------- # tempfile.gettempdir() は # そのOSで安全に利用できる一時ディレクトリのパスを # 返してくれる。 # ---------------------------------------------- pr('gettempdir', tempfile.gettempdir())
def exec(self): # # csvモジュールを利用してファイルに書き込みを行う場合に # open() に newline='' を付与していないと # 書込み後のファイルには、自動で改行が一つ多く含まれてしまう。 # csv_path = pathlib.Path.home() / r'csv02.csv' if csv_path.exists(): csv_path.unlink() with open(csv_path, mode='wt', encoding='utf-8', newline='') as fp: writer = csv.DictWriter(fp, fieldnames=['field1', 'field2']) writer.writeheader() writer.writerow(dict(field1=100, field2=200)) writer.writerow(dict(field1=300, field2=400)) assert csv_path.exists() with open(csv_path, mode='rt', encoding='utf-8', newline='') as fp: reader = csv.DictReader(fp) for row in reader: pr('row', row) if csv_path.exists(): csv_path.unlink()
def exec(self): """処理を実行します。""" # -------------------------------------------------------------------------------- # pygments の基本的な使い方 # - http://pygments.org/ # # pygments を利用する場合、必要なオブジェクトは以下の3つ # - コード: ハイライト表示対象のコード # - 解析器(lexer): コードを解析するためのオブジェクト # - フォーマッタ: 最終的な出力を担当するオブジェクト # # lexer と formatter は、各実装クラスを直接つかってもいいが # 以下のヘルパー関数を使用しても取得できる # - pygments.lexers.get_lexer_by_name() # - 例えば、言語が python の場合は、"python" or "python3" となる # - http://pygments.org/docs/lexers/ # - pygments.formatters.get_formatter_by_name() # - 例えば、HTMLで出力したい場合は "html" となる # - http://pygments.org/docs/formatters/ # - HtmlFormatterは便利だが、残念な事にHTML4形式で現状出力されてしまう。 # # 必要なオブジェクトが揃ったら、後は pygments.highlight() に渡すと # 整形データが取得できる # -------------------------------------------------------------------------------- code = """\ def hello(): print('world') results = [] for x in range(10): ressults.append(i for i in x) """ lexer = get_lexer_by_name('python3') formatter = get_formatter_by_name('html', linenos=True, full=True, encoding='utf-8') # formatter に対して, 共通パラメータ [encoding] を指定した場合 # 結果として受け取るデータの型は、bytes になる。指定していない場合、str となる。 # HtmlFormatter にて encoding を指定しない場合、 charset の値が None となることに注意。 html = highlight(code, lexer, formatter) if hasattr(html, 'decode'): html = html.decode('utf-8') pr('pygments.html', html) file_path = (pathlib.Path.home() / 'pygments_test.html').as_posix() with open(file_path, 'w') as out_fp: out_fp.write(html) preserve_file = True try: if sys.platform == 'win32': cmd = shlex.split(f'cmd /C start {file_path}') else: cmd = shlex.split(f'open {file_path}') subprocess.check_call(cmd, shell=False) finally: if not preserve_file: os.unlink(file_path)
def exec(self): # # python で yaml を扱う場合、標準モジュールには # 存在しないので、PyYAMLモジュールを利用する # with io.StringIO(YAML_TEXT) as fp: obj = yaml.load(fp, Loader=yaml.SafeLoader) pr('yaml.load()', obj)
def exec(self): # # 特殊メソッド __iter__ を実装することにより # イテレータプロトコルをサポート出来る # iter_support = IterProtocolSupport(list(range(10))) for item in iter_support: pr('item', item)
def exec(self): num = 1.00 pr('type(num)', type(num)) pr('is_integer', num.is_integer()) # ==> True (整数に出来るので) pr('int()', int(num)) num = 1.05 pr('is_integer', num.is_integer()) # ==> False (整数に出来ないので) pr('int()', int(num))
def exec(self): # # 特殊メソッド __contains__ を実装することにより # 存在判断を in で検査することが可能になる # contains_support = ContainsProtocolSupport(list(range(10))) pr('contains(5)', 5 in contains_support) pr('contains(99)', 99 in contains_support)
def access_globalvariable_with_globalcall(): # ------------------------------------------------------------ # グローバル変数を利用すると宣言 # ------------------------------------------------------------ global global_variable01 pr('global 呼び出し後にグローバル変数にアクセス', global_variable01) global_variable01 = 'hello world from func-inside' pr('値変更後', global_variable01)
def exec(self): # dataclass 定義時、フィールドの初期値を設定していないものに関してはコンストラクト時に指定が必要となる # quantity フィールドは、初期値を設定しているので設定しなくてもコンストラクト出来る. obj = Data1(name='test', unit_price=300.5) obj.quantity = 5 # __repr__ が自動生成されているので見やすい文字列表現が得られる pr('obj', obj) # もちろん普通のクラスと同様に自分で定義したメソッドも利用可能 pr('obj.total_cost', obj.total_cost())
def decorator_function(*args, **kwargs): pr('decorator', func.__name__, 'func-name') pr('decorator', args, '*args') pr('decorator', kwargs, '**kwargs') result = func(*args, **kwargs) pr('decorator', result, 'result') pr('----------------------------------', '') return result
def exec(self): self.access_globalvariable_without_globalcall() self.access_globalvariable_with_globalcall() # # 組み込み関数の locals() と globals() でそれぞれの内容を見ることが出来る # local_variable = 'local val' pr('locals()', locals()) pr('globals()', globals())
def atomic_regex_module(self): """Python の 標準モジュール re は、アトミックグループをサポートしていない。 http://bit.ly/2O3jVNn に記載されているように、無理やり評価させることも可能 らしいのだが、「regex」モジュールを pip でインストールして利用する方が楽。 「regex」モジュールは、(?>pattern)の書式をサポートしている。 """ global _message m = regex.match(r'(?>\d*):', _message) if m: pr('atomic_regex_module', 'マッチした') else: pr('atomic_regex_module', 'マッチしない')
def heavy_proc(value: str, sleep_seconds: int) -> dict: start_dt = NOW() pid = os.getpid() pr('start', f'pid: {pid} [{value}] sleep: {sleep_seconds}') time.sleep(sleep_seconds) pr('end', f'pid: {pid} [{value}]') end_dt = NOW() return { 'pid': pid, 'elapsed': (end_dt - start_dt).seconds }
def access_globalvariable_without_globalcall(): try: # ------------------------------------------------------------ # グローバル変数を見るだけなら可能。 # 以下の2行のうち、2行目をコメントアウトすると # エラーにはならない。 # ------------------------------------------------------------ # noinspection PyUnresolvedReferences pr('global 無しでグローバル変数にアクセス', global_variable01) global_variable01 = 'hello world from func-inside' except UnboundLocalError as e: pr('global無しでグローバル変数を書き換えようとするとエラーとなる', e)
def exec(self): # # secretsモジュールは、3.6から追加された標準モジュール # 文字通りセキュアな値を管理することを目的としている # # パスワードやトークンの生成時に利用できる # # 参考URL: # https://www.blog.pythonlibrary.org/2017/02/16/pythons-new-secrets-module/ # pr('generate passwd', self.generate_password(32)) pr('url_token', secrets.token_urlsafe(32))
def exec(self): # # vars() は、引数無しで呼ぶと locals() と同じ # 引数を付与して呼ぶと、そのオブジェクトの __dict__ を返す # x = 10 y = 20 pr('vars()', vars()) self.fn01(10, 20, 30, **dict(apple=100, pineapple=200)) Sample.fn02(10, 20, 30, **dict(apple=100, pineapple=200)) Sample.fn03(10, 20, 30, **dict(apple=100, pineapple=200))
def exec(self): obj = Data1(name='test', unit_price=300.5) try: # -------------------------------------------------------- # frozen 指定している dataclass は値の設定が出来ないようになる. # dataclasses.FrozenInstanceError が発生する. # -------------------------------------------------------- # noinspection PyDataclass obj.quantity = 5 except dc.FrozenInstanceError as e: pr('frozen な dataclass に値を設定', e)
def exec(self): # ------------------------------------------------------- # sys モジュール # ------------- # sys.executable から、現在動作中の python インタープリタの # 絶対パスが取得できる。 システムに複数の python がインストールされていたり # venv 環境下で作業している場合に、実行パスを間違えないように # ここから取得するほうが良い。 # ------------- # subprocess モジュールを使って、内部から別プロセスで python を起動する際にも # sys.executable からパスを取得して起動すれば間違いがない。 # ------------------------------------------------------- pr('sys.executable', sys.executable)
def exec(self): # -------------------------------------------- # venv で仮想環境を作り、 activate している状態だと # sys モジュールの prefixとbase_prefixの値が異なる # 状態となる。仮想環境を使っていない場合、同じ値となる. # -------------------------------------------- pr('prefix', sys.prefix) pr('exec_prefix', sys.exec_prefix) hr() pr('base_prefix', sys.base_prefix) pr('base_exec_prefix', sys.base_exec_prefix) pr('venv 利用している?', sys.prefix != sys.base_prefix)
def exec(self): # 基本的なやり方 target_str = 'abcede hello world 12345' items = 'z y x hello'.split() for x in items: if x in target_str: pr('basic', f'found: {x}') # any を使ったやり方 found = any(x in target_str for x in items) if found: pr('any', f'found')
def exec(self): # # jsonモジュールには load() と dump() がある # また、文字列で処理するための loads(), dumps() もある # file_path = pathlib.Path('sample01.json') with open(file_path) as fp: json_object = json.load(fp) pr('json', json_object) languages = json_object['languages'] pr('language', [item['language']['name'] for item in languages])