#author("2024-10-31T17:58:30+09:00","default:okazaki","okazaki")
#author("2024-11-07T10:49:13+09:00","default:okazaki","okazaki")
#menu(howto/MenuBar)
* howto/python [#i439c96a]
#contents
** コメント [#ffd23d8f]
- "Fortran, C ユーザに向けた実践的 Python プログラミング" https://www.cc.kyushu-u.ac.jp/scp/doc/users/lecture/2016/riit_lecture160824_python_rev16251200.pdf --  &new{2019-10-01 (火) 07:40:13};
-- 基本、NumPy, SciPy, MPI並列, ライブラリ(.so等)内の関数利用, LAPACK利用, 各種インストール の説明あり

- pythonでは i++はできないので、i+=1 --  &new{2021-08-26 (木) 09:46:13};

- numpy.linspace(0,10,5)  # 0と10を含む5要素のリスト --  &new{2021-08-30 (月) 16:22:40};

- デコレータ(@hogehoge) https://qiita.com/mtb_beta/items/d257519b018b8cd0cc2e https://zenn.dev/ryo_kawamata/articles/learn_decorator_in_python --  &new{2021-09-08 (水) 16:09:25};
 (例)
 from functools import wraps
 def trace( func ):
     @wraps( func )  # 問題を起こさないように、wrapsでメタデータを複製しておく。
     def wrapper( *args, **kwargs ):
         result = func( *args, **kwargs )
         print( f"{func.__name__}( {args}, {kwargs} ) -> {result}" )
         return result
     return wrapper
 @trace
 def fib( n ):
     """return fibonacci number"""
     if n in ( 0, 1 ):
         return n
     return fib(n-2) + fib(n-1)
 #fib = trace(fib)
 #trace(fib)(4)
 print( fib(4) )
 help( fib )
 print( fib )

- アインシュタインの和の規則みたいなものをする numpy.einsum https://qiita.com/d-takagishi/items/94e47ecd1abc54978b44 --  &new{2021-09-08 (水) 16:40:47};
- assert( 条件式 )  が使える --  &new{2021-09-08 (水) 17:08:32};

- pythonのオブジェクト解説 https://postd.cc/pythons-objects-and-classes-a-visual-guide/ (青矢印はクラス継承、黒矢印はインスタンス生成) --  &new{2021-09-13 (月) 16:40:30};


- try、Tkinter、浅いコピー、簡易テキストエディタ作成、NumPy、SciPy、Matplotlib、pandas、名前空間、docstring、ミュータブルなど
-- プログラミング演習 Python 2019 (喜多 一) https://repository.kulib.kyoto-u.ac.jp/dspace/bitstream/2433/245698/1/Version2020_02_13_01.pdf
-- プログラミング演習 Python 2019(コラム編) (同) https://repository.kulib.kyoto-u.ac.jp/dspace/bitstream/2433/245698/2/Version2020_02_13_02.pdf



- イテレータからイテレータを呼んでいる例 --  &new{2021-09-15 (水) 21:02:02};
 def myg( itarg ):
     for i in [ 0, 1, 2, 3, 4 ]:
         try:
             yield str(i)+"+"+next(itarg)
         except StopIteration:
             print( "STOP in myg" )
             break
         except:
             print( "OTHER" )
 def myf():
     for i in [ "a", "b", "c", "d"+"e" ]:
         yield i
 it = myg( myf() )
 for i in range(0,10):
     try:
         o = next( it )
         print( o )
     except StopIteration:
         print( "STOP" )
         break
     except:
         print( "OTHER" )
- del インスタンス  #インスタンスを削除する --  &new{2021-10-07 (木) 09:54:57};
- a[0][:,0] と a[0][:][0] は違う結果になるようだ。 --  &new{2021-10-08 (金) 20:07:29};

- ブロードキャスト: たとえば、サイズの異なる配列間の演算に出てくる概念のこと --  &new{2022-03-13 (日) 19:37:49};
- numpyにloadtxtというのがあり、列ごとにコンバーター converters = {0: datestr2num} などを渡せる。 --  &new{2022-06-22 (水) 21:17:08};
- クラスについての説明と名前空間の話し(python.org) https://docs.python.org/ja/3/tutorial/classes.html --  &new{2022-06-23 (木) 10:55:17};
 (例)
 #import copy
 class Warehouse:
     purpose = 'storage'
     region  = 'west'
     tricks  = [ 'init' ]  #全てのインスタンスで共有されてしまう(mutableなオブジェクトを代入した場合。
                           #オブジェクトのポインタが代入されてるようなもの。)
                           #名前空間と関係するようだが、よくわからん。
     #tricks = copy.deepcopy( [ 'init' ] )  #オブジェクトをコピーしたところで意味は無い
     #self.tricks  = [ 'init' ]  #文法エラー
     def add_trick( self, t ): self.tricks.append( t )
     def initialize( self ):
         self.purpose = 'storage'
         self.regaion  = 'west'
         self.tricks  = [ 'init' ]
         self.__init__()
     def __init__( self ):
         self.floor = '2F'
 
 w1=Warehouse()
 w2=Warehouse()
 print( (w1.purpose, w1.region, w1.floor, w1.tricks) )
 print( (w2.purpose, w2.region, w2.floor, w2.tricks) )
 -> ('storage', 'west', '2F', ['init'])
 -> ('storage', 'west', '2F', ['init'])
 
 w2.region = 'east'; w2.floor = '5F'; w2.add_trick( "play" )                                                        
 print( (w1.purpose, w1.region, w1.floor, w1.tricks) )
 print( (w2.purpose, w2.region, w2.floor, w2.tricks) )
 -> ('storage', 'west', '2F', ['init', 'play'])
 -> ('storage', 'east', '5F', ['init', 'play'])
 
 w2.initialize()
 print( (w1.purpose, w1.region, w1.floor, w1.tricks) )
 print( (w2.purpose, w2.region, w2.floor, w2.tricks) )
 w1.initialize()
 print( (w1.purpose, w1.region, w1.floor, w1.tricks) )
 print( (w2.purpose, w2.region, w2.floor, w2.tricks) )
 -> ('storage', 'west', '2F', ['init', 'play'])
 -> ('storage', 'east', '2F', ['init'])
 -> ('storage', 'west', '2F', ['init'])
 -> ('storage', 'east', '2F', ['init'])
- goto文の代用 --  &new{2022-06-28 (火) 11:12:12};
-- https://note.nkmk.me/python-break-nested-loops/
-- [[https://www.web-dev-qa-db-ja.com/ja/python/pythonにラベル-gotoはありますか?/958125936/>https://www.web-dev-qa-db-ja.com/ja/python/python%E3%81%AB%E3%83%A9%E3%83%99%E3%83%AB-goto%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F/958125936/]]
- print(*map(lambda x: '"{}"'.format(x), '日月火水木金土'), sep=',')  #個々の文字を引用符 " で括って、*により個々にprintの引数として渡される --  &new{2022-06-28 (火) 11:19:24};

- (memo)Visual Studio Code --  &new{2022-06-29 (水) 17:54:11};
-- https://qiita.com/kusanoiskuzuno/items/c323446f2707f9950ebb
-- https://code.visualstudio.com/#alt-downloads
-- https://code.visualstudio.com/docs/supporting/requirements
-- https://qiita.com/IntenF/items/dbfe1bef4568719a0133
- 字句/構文解析ライブラリ  https://qiita.com/shinsa82/items/94d800df630e63511014 --  &new{2022-06-29 (水) 20:06:39};
- scikit-learnライブラリ https://utokyo-ipp.github.io/7/7-2.html --  &new{2022-07-03 (日) 11:12:16};
- 数値が整数か小数かを判定 https://note.nkmk.me/python-check-int-float/ --  &new{2022-07-12 (火) 09:29:03};
- a is None  #変数aがNoneであればTrueを与える --  &new{2022-07-12 (火) 09:50:17};
- numpy、配列の比較 https://nishidy.hatenablog.com/entry/2016/04/23/120519 --  &new{2022-07-14 (木) 07:47:45};
- Pythonプログラミング入門 https://utokyo-ipp.github.io/ --  &new{2022-07-14 (木) 08:03:53};
- gnuplotの呼び出し --  &new{2022-09-08 (木) 18:22:14};
 >>>>import subprocess
 >>> p=subprocess.Popen( ['gnuplot' ], bufsize=0, stdin=subprocess.PIPE )
   #bufsize=0 で、下で p.stdin.flush() は不要になる。
   #stdout=None, stderr=None(デフォルト)のときは、サブプロセスの出力は端末に出る。
 >>> a=input()
 plot tan(x)
 >>> p.stdin.write( a.encode() ); p.stdin.write( "\n".encode() )
 >>> a=input()
 quit
 >>> p.stdin.write( a.encode() ); p.stdin.write( "\n".encode() )
 
 その他のメモ
 >>> subprocess.call( [ 'gnuplot' ] )   #gnuplotのプロンプトが来る。
 >>> subprocess.call( [ 'gnuplot', "-e", "plot sin(x); pause 2", "script1", "script2", "-", "script3", "-", "script4" ] )
   #スクリプトの実行など(scriptNのファイルの中は print "scriptN" などの gnuplotのスクリプト)。
   #- の標準入力のときには gnuplotのプロンプトが来る。
- https://repo.anaconda.com/ --  &new{2022-11-09 (水) 11:35:10};
- PyQt4 https://myenigma.hatenablog.com/entry/2016/01/24/113413#Window%E3%82%92%E4%BD%9C%E3%82%8B --  &new{2022-11-13 (日) 04:06:52};
- tkinter https://myenigma.hatenablog.com/entry/2017/09/15/150945#Window%E3%82%92%E4%BD%9C%E3%82%8B --  &new{2022-11-13 (日) 04:07:59};
- Qt Desinger https://showa-yojyo.github.io/notebook/python-pyqt5.html#qt-desinger --  &new{2022-11-13 (日) 04:11:42};
- PyQt5 https://ops.jig-saw.com/tech-cate/pyqt_graph (ウィンドウを出してみよう、から) --  &new{2022-11-13 (日) 04:13:33};
- たぶん再掲(pythonによるParaViewの操作) --  &new{2022-11-13 (日) 05:45:46};
-- https://www.opencae.or.jp/wp-content/uploads/2015/06/course20111201handout.pdf
-- https://ss1.xrea.com/penguinitis.g1.xrea.com/study/ParaView/Python/Python.html
-- https://www.rccm.co.jp/icem/pukiwiki/?%E6%93%8D%E4%BD%9C%E3%81%AE%E8%A8%98%E9%8C%B2
- PyQt5, Quick Guide https://www.tutorialspoint.com/pyqt5/pyqt5_quick_guide.htm --  &new{2022-11-17 (木) 06:59:10};
- PyQt5など --  &new{2022-11-22 (火) 12:38:44};
-- https://qiita.com/montblanc18/items/0188ff680acf028d4b63
-- https://www.sejuku.net/blog/75467
-- https://www.xsim.info/articles/PySide/how-to-layout.html
-- https://www.naka-sys.okinawa/python-pyqt-gui-devlop/
-- https://myenigma.hatenablog.com/entry/2016/01/24/113413
-- https://zetcode.com/gui/pyqt5/
-- https://www.riverbankcomputing.com/static/Docs/PyQt5/ (リファレンスガイド)
-- https://github.com/diego0020/tutorial-vtk-pyqt (VTKとPyQt)--  &new{2022-11-22 (火) 12:41:36};
- from apackage import * を使用したとき、パッケージの__init__.py内の__all__で指定されているものがimportされるらしい。 --  &new{2022-11-29 (火) 15:33:14};
- hoge.pyをfrom hoge import * することもできる。 --  &new{2022-11-29 (火) 16:48:58};
- matplotlibのAPI説明など https://matplotlib.org/stable/api/index.html , https://matplotlib.org/stable/users/index.html , https://matplotlib.org/ --  &new{2022-12-22 (木) 09:54:20};
- Tcl/Tk の Python インタフェース https://docs.python.org/ja/3.7/library/tkinter.html?utm_source=pocket_reader --  &new{2023-02-07 (火) 23:38:46};
- os.listdir().sort() のオブジェクトには、iterateのメソッドが含まれない --  &new{2023-03-31 (金) 22:33:55};
- subprocess.runの例 --  &new{2023-04-01 (土) 17:27:11};
 a = "input-data-hogehoge"
 r = subprocess.run( "cat", shell=True, input=a.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE )
 print( "a=", a )
 print( "stdout=", r.stdout.decode() )
 print( "stderr=", r.stderr.decode() )
- emacsでリージョンのインデントを変更する --  &new{2023-04-17 (月) 15:39:32};
 C-c <    M-x python-indent-shift-left   インデント変更
 C-c >    M-x python-indent-shift-right  インデント変更
- jupyter notebookでinteractiveにグラフを変更する --  &new{2023-05-16 (火) 15:36:35};
 import numpy, matplotlib.pyplot, ipywidgets, math
 
 @ipywidgets.interact( m=(-20,20,1) ) #min,max,step
 def f(m=2.0):
     x=numpy.linspace(-10,10)
     y=numpy.power(x,m)
     #print(x)
     #print(y)
     #matplotlib.pyplot.xlim(-10,10)
     matplotlib.pyplot.plot(x,y)
- その他interactiveの例
-- https://ebi-works.com/jupyternb-gui/
-- https://toyoki-lab.ee.yamanashi.ac.jp/~toyoki/lectures/simulationMethods/ipywidgetsExamples.html
- 実例つき、QWidget 逆引きリファレンス https://tadosuke.com/programming/4547/ --  &new{2023-07-21 (金) 22:08:13};
- https://ja.wikipedia.org/wiki/PyQt --  &new{2023-07-21 (金) 22:28:35};
- https://riverbankcomputing.com/software/pyqt/ から-> "PyQt5 Reference Guide" -> "list of modules" -> "QtWidgets" -> このモジュールの各クラスのマニュアル(不十分) --  &new{2023-07-21 (金) 22:28:54};
- QWidgetを継承した画面開発のテンプレート https://tech.nkhn37.net/pyqt-qwidget-program-template/ --  &new{2023-07-21 (金) 22:32:32};

- フーリエ変換の例 --  &new{2023-08-03 (木) 17:09:18};
 import cmath
 N = 8
 x = []
 for k in range(0,N):
     x.append( 1/cmath.sqrt(N) )  #区間[0,1]をN等分して、全てに1/√8のデータをセット
 
 y = []  #フーリエ変換
 for k in range(0,N):
     a = 0.0
     for j in range(0,N):
          a = a + 1/cmath.sqrt(N)*x[j]*cmath.exp( 1J*2*cmath.pi*k*j/N )  #1/√N倍している
     y.append( a )
 print( "FT" )
 a = 0.0; b = 0.0
 for k in range(0,N):
     print( "{: >5d} {: >20.4f} {: >20.4f}".format( k, x[k], y[k] ) )
     a = a + cmath.polar( x[k] )[0] **2
     b = b + cmath.polar( y[k] )[0] **2
 print( "power = {: >15.4f}      {: >15.4f}".format(a, b) )
 
 x = []  #逆フーリエ変換
 for j in range(0,N):
     a = 0.0
     for k in range(0,N):
          a = a + 1/cmath.sqrt(N)*y[k]*cmath.exp( -1J*2*cmath.pi*k*j/N )  #1/Nでなく1/√N倍している
     x.append( a )
 print( "Inverse FT" )
 for k in range(0,N):
     print( "{: >5d} {: >20.4f} {: >20.4f}".format( k, x[k], y[k] ) )
- Python3簡易資料 https://blackknight.ics.nara-wu.ac.jp/pub/doc/python3.pdf --  &new{2023-08-30 (水) 11:25:47};
- openしたときのストリームインスタンスの型とreadlineメソッド --  &new{2023-08-30 (水) 13:11:27};
 python仮想環境で
 (py3913) allium$ python3
 >>> f=open("hoge.vti","r")  #"rt"と同じでテキストモード読込
 >>> type(f)
 <class '_io.TextIOWrapper'>
 >>> type(f.buffer)
 <class '_io.BufferedReader'>
 >>> f.encoding  #encoding属性を持つ(_io.BufferedReaderは持たない)
 'UTF-8'
 >>> f=open("hoge.vti","rb")  #バイナリモード読込
 >>> type(f)
 <class '_io.BufferedReader'>
 
 同じく仮想環境で、
 (py3913) allium$ python -m pydoc _io.TextIOWrapper
 (py3913) allium$ python -m pydoc _io.BufferedReader
 により f.readline() と f.buffer.readline()のドキュメントを見ることができる。
 _io.TextIOWrapper の readline
   Read until newline or EOF.
   Returns an empty string if EOF is hit immediately.
 _io.BufferedReader の readline
  Read and return a line from the stream.
  If size is specified, at most size bytes will be read.
  The line terminator is always b'\n' for binary files; for text
  files, the newlines argument to open can be used to select the line
  terminator(s) recognized.
- 色空間変換パッケージ https://pypi.org/project/colorspacious/ (CIELab→sRGBなど) --  &new{2023-10-13 (金) 17:30:11};
- バイトコンパイル・コンパイル --  &new{2024-04-04 (木) 15:10:00};
 バイトコンパイル 
    $ python3 -m compileall *.py
    __pycache__に.pycが作られる。
 マシンコードにコンパイルすることもできるようであるが、
 通常のpythonで使える文法の範囲が極端に狭まってしまうようだ。
- ver 3.7未満でファイルの先頭で if sys.version_info < ( 3, 7 ) : sys.exit("ERROR") をしても f-stringがあると文法エラーになるため、先頭にコードを追加するだけではバージョンチェックはできなさそう。 --  &new{2024-05-18 (土) 15:39:38};
- f-stringsを使えないバージョンのpythonで、バージョンが古いというエラーメッセージを出すには次の方法がよさそうである(ファイル先頭でversion_infoを調べても、後方にf文字があるとそこで文法エラーが出て期待するエラー処理が行われないため) --  &new{2024-05-20 (月) 18:04:09};
 # check python version
 dummy_f_string = f"PLEASE USE PYTHON 3.7 OR LATER if you get SyntaxError."
 import sys
 if sys.version_info < ( 3, 7 ) :
     sys.exit( "ERROR: python -v < 3.7" )
- ネットワーク(ノードとエッジ図)のインタラクティブな可視化: https://qiita.com/mitch0807/items/0314a793192b69f5771c + https://qiita.com/baby-degu/items/bf97545595a781050cb5 --  &new{2024-05-28 (火) 09:38:08};
- p=1e+14; print( f'{p: >+12.2g}')  #f文字列と書式の例(.formatと同じようだ) --  &new{2024-05-30 (木) 17:52:16};
- disモジュール(逆アセンブルの結果を見る) https://qiita.com/AkariLuminous/items/ab3f382643e92122f8ef#31-%E8%AA%BF%E3%81%B9%E3%82%8B%E6%96%B9%E6%B3%95 --  &new{2024-06-16 (日) 13:20:19};
- べき乗は**を使う 2.73*10**2  #mathematicaは 2.73*^2 --  &new{2024-06-16 (日) 13:23:58};
- Pythonでは、プログラムを起動したディレクトリが自動的にPythonのモジュール検索パスに含まれるらしい。[chatgpt] --  &new{2024-11-07 (木) 10:49:13};

#comment

//--------------------------------------------------------------------------------

** ドキュメント [#dca7f077]

- Python標準ドキュメント http://www.python.jp/
(メニューのドキュメントに和訳ドキュメントがある。全モジュール索引もあり)
- Python早見帳 https://chokkan.github.io/python/index.html (Python言語の説明)
- 特殊メソッドの一覧 https://qiita.com/y518gaku/items/07961c61f5efef13cccc 
( __add__ が + 演算子であるなど)

- pydoc オンラインヘルプ
 python -m pydoc  -n `hostname` -p 8801  #その後 webブラウザで http://`hostname`:8801に接続
 python -m pydoc sys

- ヘルプ関係の関数など
 dir( hoge )  #オブジェクトの属性を調べる。引数無しだと、現在のスコープの属性を返す。
 help( hoge ) #オブジェクトのドキュメントを調べる(ドキュメンテーションが書かれていれば)
 
 type( hoge )  # オブジェクトの型を知る。
               # type, function, methodなどが返ってきたら、クラス、関数、クラスメソッドなどのようだ
 type( hoge ).mro()  # 何のクラスのインスタンスかが出るようだ(クラス継承含む)
 
 hoge.dtype  #numpy.ndarray型のオブジェクトであるhogeの要素のデータ型を調べる

-- 例
 >>> b=open( "hogehoge.readme", "r" )
 >>> c=b.read(16);  print(c);  b.close()  #readで16文字読み込み
 >>> help( b.read )  #説明

-- オブジェクトがどのクラスインスタンスであるかであるか知る(例1)
 a = Hoge()  # クラスHogeのインスタンスとして、オブジェクトを生成
 
 type(a) == Hoge  # aがクラスHogeのインスタンスの場合、真。 a.__class__ == Hoge でも同じ。
 isinstance( a, Hoge )  # aが、クラスHoge又は Hogeを継承したクラスであれば、真
 
・https://www.lifewithpython.com/2014/06/python-check-object-instance-class-relationship-by-type-isinstance.html #何のクラスのインスタンスかを知る~
・https://docs.python.org/ja/3.7/library/inspect.html # import inspect で、オブジェクトについていろいろ調べられるようである~

-- オブジェクトがどのクラスインスタンスであるかであるか知る(例2)
 from pyscf import gto, scf
 mol=gto.M( atom='H 0 0 0; H 0 0 1.4', basis='sto-3g' )
 mf=scf.RHF( mol )
 mf.kernel()
 
 type( gto )  # moduleと返るので、モジュール
 type( scf )  # moduleと返る
 gto.__file__  # moduleがどのファイル(ディレクトリ階層と__init__.py)かがわかる
 
 type( gto.M )  # functionと返るので、関数
                # def Mの定義は、ディレクトリ階層内や__init__.pyにあるはず
 
 type( mol )        # pyscf.gto.mole.Moleと返るので、そのクラスのインスタンスらしい
 type( mol ).mro()  # 何のクラスのインスタンスかが出るようだ(クラス継承含む)
 => [pyscf.gto.mole.Mole, pyscf.lib.misc.StreamObject, object]
 #type( gto.mole.Mole )  # typeと返り、クラスらしい(インスタンスではないため、mro()は使えない)
 
 type( scf.RHF )  # functionと返るので、関数
 type( scf.RHF ).mro()
 => [function, object]
 
 type( mf )      # pyscf.scf.hf.RHFと返るので、このクラスのインスタンスらしい
 type(mf).mro()
 => [pyscf.scf.hf.RHF, pyscf.scf.hf.SCF, pyscf.lib.misc.StreamObject, object]
 
 type( mf.kernel )  # methodと返るので、クラスメソッド
 type( mf.kernel ).mro()
 => [method, object]






** 命名の慣例 [#iac36e1f]

 2022/06/26+α
 
 pythonでの命名の慣例
 
 * 先頭に _ をつけたものは外部から書き換え禁止。
 
 * 先頭に __ をつけたものはアクセス禁止。
 
 * 関数名は すべて小文字でスネークケース(単語をつなげる場合は _ でつなぐ)。
 
 * 変数は すべて小文字でスネークケース。
 
 * クラス名は アッパーキャメルケース(大文字から始め、単語をつなげる場合は最初を大文字にしてつなぐ)。
   クラスのメソッドの第1引数は selfにする
 
 * 定数は すべて大文字でスネークケース。
 
 * 破棄変数として _ 名のみの変数がある。eg) for _ in range(10): print( "hello" )
 
 * 名前の末尾 _ は名前衝突を避けるために使用される(末尾 __ や  ___ なども)。
 
 * 名前の先頭と末尾 __...__ はpythonが特別な用途として使っているもの。eg) __init__
 
 * パッケージ名は すべて小文字の短い名前で _ は使わない。
   なお、パッケージ名はディレクトリ名やファイル名に対応している。
   eg) import tkinter の tkinter
   eg) import turtle の turtle
 
 * モジュール名は すべて小文字の短い名前で _ を使ってもよい。
   なお、モジュール名は拡張子を除いたファイル名に対応している。
   eg) import tkinter.font の font

[ref]~
https://qiita.com/shiracamus/items/bc3bdfc206b39e0a75b2 ~
https://mako-note.com/ja/python-underscore/ ~
https://python.softmoco.com/basics/python-naming-conventions.php ~

** tkinerモジュール [#xd2790e9]

(注) python2は Tkinter、python3は tkinterを importするようだ。名前が異なる。

%%お気楽 Python/Tkinter 入門%%
%% http://www.geocities.jp/m_hiroi/light/pytk01.html %%

1. Hello world!
http://www.shido.info/py/tkinter1.html

PythonのTkinterを使ってみる
https://qiita.com/nnahito/items/ad1428a30738b3d93762


** 実行時間を測る、sleepする [#l5cdfcc5]

 >>> import time
 >>> time1 = time.clock()
 >>> time2 = time.clock()
 >>> print( time2 - time1 )
 0.0009600000000000164
 >>>
 >>> help( time ) #ドキュメントをみる
 >>> time1 = time.clock(); time.sleep(10); time2 = time.clock(); print( time2 - time1 )
 4.599999999999049e-05
 
 time.clock()は3.8?から廃止されているので time.time()を使う。

 sleepを使う。import time しておいて、time.sleep(2)など


** いくつかの例 [#r7174bd4]

インタプリタ起動
 $ python  #たいていpython2が起動するらしい
 $ DISPLAY=hostname:0 python3 -B  #python3を起動、バイトコンパイルさせない(-Bオプション)、DISPLAYを指定。
 
 $ export PYTHONDONTWRITEBYTECODE=t  #これでもバイトコンパイルさせないらしい

スクリプトの実行
 $ DISPLAY=hoge:0 python3 -B filename.py  #filename.pyを実行する。
 $ DISPLAY=hoge:0 ./filename.py           #filename.pyを実行する。

いくつかの例
 >>> from turtle import *
 >>> for i in range(6):    #図形が表示される
 ...     forward(100)
 ...     right(60)
 ... 
 >>> a = "Python3 is awsome!"
 >>> a . lower()
 'python3 is awsome!'
 >>> len(a)
 18
 >>> (1+2J)/5J
 (0.4-0.2j)
 >>> for item in [ 'a', 'b', 'c' ]:
 ...     print( item )
 ... 
 a
 b
 c
 >>> for c, item in enumerate( [ 'a', 'b', 'c' ] ):
 ...     print( c, item )
 ... 
 0 a
 1 b
 2 c
 >>> f=open("temp.txt", "w")
 >>> for c in range(1,101):    #1から100までの数字をファイルに書き出す。
 ...     f.write( str(c) )
 ... 
 >>> f.close()
 >>> [ord(s) for s in "Python"]    #内包記法で文字コードのリストを作る
 [80, 121, 116, 104, 111, 110]
 >>> val=10; [ x for x in range(1,val+1) if val %x == 0 ]    #内包記法で10の約数のリストを作る
 [1, 2, 5, 10]

 #二次元配列を作る
 >>> a = [ [ str(i)+str(j) for j in range(8)]  for i in range(5) ]
 >>> a
 [['00', '01', '02', '03', '04', '05', '06', '07'], ['10', '11', '12', '13', '14', '15', '16', '17'], 
 ['20', '21', '22', '23', '24', '25', '26', '27'], ['30', '31', '32', '33', '34', '35', '36', '37'], 
 ['40', '41', '42', '43', '44', '45', '46', '47']]
 >>> a[4][5]
 '45'
 >>> int(a[4][5])
 45
 >>> for i in range(5):
 ...   a[i]
 ...
 ['00', '01', '02', '03', '04', '05', '06', '07']
 ['10', '11', '12', '13', '14', '15', '16', '17']
 ['20', '21', '22', '23', '24', '25', '26', '27']
 ['30', '31', '32', '33', '34', '35', '36', '37']
 ['40', '41', '42', '43', '44', '45', '46', '47']


 >>> i = { "GMT" : "+000", "BST" : "+100", "EET" : "+200", "JST" : "+900" }
 >>> i
 {'BST': '+100', 'EET': '+200', 'JST': '+900', 'GMT': '+000'}
 >>> i.items()
 dict_items([('BST', '+100'), ('EET', '+200'), ('JST', '+900'), ('GMT', '+000')])
 ### dict_items(  ) が付く意味はなに? 辞書型インスタンスの特殊メソッド__repr__の単なる仕様?

 >>> import os
 >>> os.walk("./")
 >>> i=os.walk("./")
 >>> next(i)
 ('./', ['QCLObot', 'ProteinDF_bridge', 'ProteinDF', 'ProteinDF_pytools', 'OpenFOAM', 'LOG_kiku'], 
 ['2dn2.pdb', '1omb-mod.pdb', 'LOG_kiku.tar', 'p3.py~', 'p3.py', 'temp.txt', 'fws.gro.pdb'])
 >>> next(i)
 ('./QCLObot', ['.git', 'qclobot', 'scripts'], ['.gitignore', 'LICENSE', 'setup.py', 'README.md'])
 ### 現在作業中のディレクトリ、作業中ディレクトリ内のディレクトリのリスト、作業中ディレクトリ内の
 ### ファイルのタプルがイテレータ(next(i))で次々と得られる。

 >>> from decimal import Decimal
 >>> Decimal( '0.1' ) * 3
 Decimal('0.3')
 ### この*はDecimalクラスの特殊メソッド __mul__が使われている。Decimalのインスタンスが生成され(値0.1)、
 ### __mul__が引数3で動いている。演算結果は __repr__で表示か。

 >>> import sys
 >>> sys.getfilesystemencoding()
 'utf-8'
 >>> sys.float_info
 sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308,
 min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15,
 mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

スクリプトの例
 --------------------------------------------------
 #!/usr/bin/env python3                                                                                                     
 #-*- coding:utf-8; -*-                                                                                            
 import sys
 
 def spamfactory( times ):
     """ スパム工場                                                                                                         
     """
     return "Spam ! " * times
 
 print( spamfactory( 3 ) )
 input()
 --------------------------------------------------
 $ ./p3.py
 
 --------------------------------------------------
 #!/usr/bin/env python3                                                                                            
 #-*- coding:utf-8; -*-                                                                                            
 import os
 
 #p= "./LOG_kiku"                                                                                                  
 p= "./"
 
 for path, dirs, files in os.walk( p ):
     for f in files:
         print( path, ":", f )
 --------------------------------------------------
 $ ./p4.py

みんなのPython 第3版, 柴田亨, SBクリエイティブ (2012) 14章の例、
ファイルはここちら 
[[todoapp.tar>https://orange.eit.hirosaki-u.ac.jp/pw151/index.php?LABO/%E3%81%84%E3%81%8F%E3%81%A4%E3%81%8B%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%BD%AE%E3%81%8D%E5%A0%B4#pbbdc599]]

 #正規表現を使ったファイル一覧の取得
 >>> import glob
 >>> print glob.glob('/dev/sd?')
 ['/dev/sda', '/dev/sdb']
 
 その他、個々に置換するとき
 >>> import re
 >>> [ re.replace('/dev/','') for s in glob.glob('/dev/sd?') ]
 ['sda', 'sdb']


** 基本 [#w45c8860]

*** 組み込みデータ型 [#f93ebd39]
 整数  
 浮動小数点  
 複素数  
 文字列  
 リスト  [ 1, 2, 3 ]
 タプル  ( 1, 2, 3 )   要素ひとつの場合は ( 1, )とする。( 1 ) = 1 = 整数の値などとなるため
 ディクショナリ { k1:v1, k2:v2, k3:v3 }
 bytes型  
 bool型  
 set型  { 1, 2, 3 }
 iter  イテレート可能なインスタンスに変換する
 
 備考:
 順番があるものが、シーケンス型。
 書き換えが可能なものが、書き換え可能型。
 書き換え可能でない型は、文字列、タプル(ただし要素追加は可能)と、数値もである(丸ごとの書き換えは可)。
 関数の引数は、関数で値を書き換えても、呼び出し元では変わらない(値渡しに相当)。書き換え
 可能なものもある(例:リストを渡して、リストの要素を書き換えると呼び出し元でも変更されている)。

*** 型変換 [#gef482c7]
 int()  文字列を数値に変換
 float() 
 str()  
 chr()  数値を文字(列)に変換
 hext  数値を16進数に変換
 bin  数値を2進数に変換
 oct  数値を8進数に変換


*** スライス [#l89629d3]
 リストのインスタンスaについて、a[2:3]などとして要素を取り出すこと。

*** lambda式 [#m7fbdaf6]
  see Python文法詳細、p197、オライリー

*** 整数除算(商) [#g9b1a36a]
 i // 2
 (iは整数だけでなく、浮動点小数でも切り捨て)

*** 文字列操作 [#m496fcb7]
 raw文字列  r"C:\path\to\file"
 split
 join

*** アンパック代入 [#kdbd609b]
  a, b = c, d  #スワップ
  return  a, b
  a, b = foo(hoge)

  x = ( 1, 2, 3, 4, 5 )
  a, *b, c = x  #最初と最後を a, cに、それ以外を bに代入
  print( f"{a}, {b}, {c}" )


*** リストのアンパック [#yb0c4c62]
 L=[1, 2, 3]
 *L  # 1, 2, 3 の並び(リストではない)
 (使用例)
   def foo( a, b, c ):
       hogehoge
   foo( *L )

*** 可変長引数 [#k0a08017]
  *args    タプル
  **kwargs ディクショナリ
 
 def a( *args, **kwargs ):
     print( "*args=", *args )
     #print( "**kwargs=", **kwargs )  # **kwargsは何?
     #print( type(**kwargs) )
     print( "args=", args )
     print( "*kwargs=", *kwargs )
     print( "kwargs=", kwargs )
     ### kwargs.pop( "hoge", default ) で値を得ることもできるらしい。
 a( 'zero', 1, 2, 3, term='TERM', val='VAL' )
 (出力結果)
 *args= zero 1 2 3
 args= ('zero', 1, 2, 3)
 *kwargs= term val
 kwargs= {'term': 'TERM', 'val': 'VAL'}

https://note.nkmk.me/python-args-kwargs-usage/


*** ゲッターとセッター(プロパティ) [#s2f31a23]
 x = property( getx, setx )  # xはアトリビュート、getx, setxはゲッターとセッターのメソッド。
                             # こうしておくと、インスタンス.xで代入や参照ができる。

例(以下をprop.pyとして保存して、コメントにあるようにpython3インタプリタで使う)
 class Prop:
     _val = None
 
     def __init__( self, arg=10.0 ):
         self._val = arg
 
     def getvv( self ):
         print( "In get, return _val/3.0" )
         return self._val / 3.0
 
     def setvv( self, arg ):
         print( "In set, set arg*3.0 to _val" )
         self._val = arg * 3.0
 
     # Prop().val で Prop().getvv() が動いたり(getter)、
     # Prop().val=arg で Prop().setvv(arg) が動いたり(setter)する。
     val = property( getvv, setvv )
 #    val = property( getvv )
 #    val = property( None, setvv )
 
     def show( self ):
         print( "In show, _val of Prop object is ", self._val )
 
 class PropAt:
     _val = None
 
     def __init__( self, arg=10.0 ):
         self._val = arg
 
     @property  # Prop().vv で次の Prop().vv()が動く
     def vv( self ):
         print( "In get, return _val/3.0" )
         return self._val / 3.0
 
     @vv.setter  # Prop().vv=arg で次の Prop().vv(arg)が動く
                 # setterはpropertyのあとに定義しなくてはならないようだ。
                 # また、propertyとsetterとで同じメソッド名の必要あるようだ。
     def vv( self, arg ):
         print( "In set, set arg*3.0 to _val" )
         self._val = arg * 3.0
 
     def show( self ):
         print( "In show, _val of Prop object is ", self._val )
 
 """
 import prop
 import importlib
 
 importlib.reload( prop )  #デバッグ用:prop.pyを修正して再度インポート
 
 # propertyを使った場合
 a=prop.Prop() ; a.show() ; a.val = 100 ; a.val ; a.show()
   # In show, _val of Prop object is  10.0
   # In set, set arg*3.0 to _val
   # In get, return _val/3.0
   # 100.0
   # In show, _val of Prop object is  300.0
 #100を入れて100を取り出しているように見えるが、
 #実際は100*3の値を保持しているインスタンスである。
 
 # @propertyを使った場合
 a=prop.PropAt() ; a.show() ; a.vv = 100 ; a.vv ; a.show()
   # In show, _val of Prop object is  10.0
   # In set, set arg*3.0 to _val
   # In get, return _val/3.0
   # 100.0
   # In show, _val of Prop object is  300.0
 """
[ref]~
https://www.nblog09.com/w/2019/01/09/python-setter-getter/ ~
https://chaika.hatenablog.com/entry/2020/12/10/083000



*** 標準エラー出力に書き出す [#rcbe37c6]
 print( "hoge", file=sys.stderr )

*** コメント [#zf4c11dc]

 #comment1

 '''
 comment2a
 '''

 """
 comment2b
 """

//--------------------------------------------------------------------------------


** python環境がらみの情報取得 [#p4a8886c]
- import sys; print( sys.version_info ); print( sys.version )  #pythonのバージョンを知る
- import os; os.environ['LD_LIBRARY_PATH']  #環境変数の値を得られる
- import sys, pprint; pprint.pprint(sys.path)  #パッケージを読み込むパス
- import sys, pprint; pprint.pprint(sys.modules)  #読み込んだモジュールの一覧を得る(builtinか、ライブラリか、パス名かなどが判る)


** import [#xacd9999]

 モジュールの検索順
 1)カレントディレクトリ
 2)環境変数PYTHONPATH
 3)標準ライブラリ
 4)site-packages

 import モジュール名
 from モジュール名 import クラス名
 他に、
 from パッケージ名 import サブパッケージ名
 from モジュール名 import 関数名
 などいろいろある。
 importは、グローバルでも、ローカルにでも可能である。

 モジュールの再読み込み
 import hoge が既に実行されていた場合、再度 import hoge をしても何も
 実行はされない。再度、実行する場合は reloadが必要。
 なお、マニュアルをみると、完全に挙動が同じなるというわけでななさそうである。
 >>> import imp
 >>> imp.reload( module )  #なお、import moduleが以前になされていること。
 
 Python3.3まではimp.reload()
 Python3.4以降はimportlib.reload()

 #importlibの例
 import importlib
 importlib.reload( dispmodule )  #既にいちどimport dispmoduleしていること

https://docs.python.org/3/library/imp.html#imp.reload
 
 import math
 math.sin( 1.23 )
 or
 from math import sin
 sin( 1.23 )

 複素数の数学関数を利用するには import cmath をする

 πは、import math ののち、math.pi

 classはモジュールの中などに定義される。モジュールを importして継承クラスを作れる。
 
 #ファイルbook.py内のBookクラスを利用する例
 from book import Book
 class Blog ( Book )
 or
 import book
 class Blog ( book.Book )
 
 クラスの初期化メソッド __init__
  ふつうは継承したクラスの初期化メソッドを super().__init__(hoge)として呼ぶ

 丸括弧で括るとインポートする複数のモジュールを複数行で書ける
 from math import ( sin,
                    cos, tan )
 #なお、mathモジュール内の他の関数なども評価されるが、名前空間には登録されていないだけ、と思われる?

 同じパッケージを、異なる別名をつけてインポートできる
 import hoge as alias1
 import hoge as alias2
 ここで __init__.pyは一回だけしか評価されない


** パッケージ [#x4e1986c]

ディレクトリ階層で束ねられたモジュールの集まり







** 関数の動的呼び出し [#wd9462a2]

モジュール mod11 の名前空間から、関数を実行するcallableの例
 for i in dir( mod11 ):
     print( "================================================", "mod11."+i )
     if i[0:1] == "_":
         print( "SKIP" )
     else:
         if callable( eval("mod11."+i) ):
             print( "RUN" )
             print( eval(  "mod11."+i ) )
             eval(  "mod11."+i+"()" )
         else:
             print( "NOT-RUN" )
             print( eval(  "mod11."+i ) )

クラスメソッドを動的に呼び出したり、引数を渡したりする例
 class Hoge:
     def hoge( self, a ):
         ...
     def meth( self ):
         ...
         eval( "self.hoge" )( a )
         ...
 のように、meth()の中で呼び出すメソッドを文字列演算等で決めることができ、
 引数も渡すことができる。
 なお、セキュリティ的に evalに渡す引数は、SQLインジェクションのようなものに
 注意する。


** 複素数の扱い [#rbf8b97c]
https://note.nkmk.me/python-complex/


** 例外処理 [#p035b324]
- 基本的なエラー一覧とその原因の確認方法 https://note.nkmk.me/python-error-message/
- 例外処理(try, except, else, finally) https://note.nkmk.me/python-try-except-else-finally/


** globalとnonlocal [#na4e8769]

- 関数内でのグローバル変数の利用~
http://www.ops.dti.ne.jp/ironpython.beginner/global.html ~
関数内で、グローバル変数に代入したいとき、関数内でglobal宣言をする。
さもないとエラーになるか、ローカル変数として扱われる。

- 違い
 global hoge    # hogeはモジュールスコープ(グローバルスコープ)のものであることを宣言
 
 nonlocal hoge  # hogeは外側、無ければ、外側の外側、外側の外側の...のスコープのもの
                # であることを宣言。
                # ただし、モジュールスコープのものであることを宣言することはできない

- 用語: クロージャ=外側のスコープの変数を参照して値を変える関数のこと?


** globalsとlocals [#t158b244]
それぞれグローバル変数、ローカル変数を表示する。追加も可。
 >>> b=10
 >>> def hoge():
 ...   c=20
 ...   print(globals())
 ...   print(locals())
 ...
 >>> globals()
 { ..., 'b': 10, 'hoge': <function hoge at 0x2adffbbe5040>}
 >>> locals()
 { ..., 'b': 10, 'hoge': <function hoge at 0x2adffbbe5040>}
 >>> hoge()
 { ..., 'b': 10, 'hoge': <function hoge at 0x2adffbbe5040>}
 {'c': 20}
 >>> globals()['d']=30
 >>> d
 30


** exec [#jf5644ed]
ソースコードを実行する。他のファイルを読み込んで実行するときは exec( open("hoge.py").read() )
デフォルトで変数は残らない。

関数内でexecにより定義された変数が、関数終了後に追加されているか消えるかを以下のように調べた。
なお、以下のコードをモジュールとして作り、importさせた場合も結果は同じだった。
 >>> import pprint
 >>> def delf():
 ...   global f
 ...   try: del f
 ...   except: pass  #1行で書けない?
 #G,Lに追加あり
 >>> (lambda: exec('f=90', globals(),None     ))(); pprint.pprint({'G':globals(),'L':locals()});delf()  #※
 >>> (lambda: exec('f=90', locals(), globals()))(); pprint.pprint({'G':globals(),'L':locals()});delf()
 #G,Lに追加無し
 >>> (lambda: exec('f=90', None,     None     ))(); pprint.pprint({'G':globals(),'L':locals()});delf()  #デフォルトの動作
 >>> (lambda: exec('f=90', globals(),locals() ))(); pprint.pprint({'G':globals(),'L':locals()});delf()
 >>> (lambda: exec('f=90', None,     locals() ))(); pprint.pprint({'G':globals(),'L':locals()});delf()
 >>> (lambda: exec('f=90', locals(), locals() ))(); pprint.pprint({'G':globals(),'L':locals()});delf()
execによりimportしても同じである。
 >>> (lambda: exec('import time,pprint; pprint.pprint({"G":globals(),"L":locals()}); time.sleep(3)'))(); \
     pprint.pprint({'G':globals(),'L':locals()})  #timeは追加無し
 >>> (lambda: exec('import time,pprint; pprint.pprint({"G":globals(),"L":locals()}); time.sleep(3)',globals()))(); \
     pprint.pprint({'G':globals(),'L':locals()})  #timeは追加あり

globals, localsの挙動がいまいちよくわからないが、変数を追加する場合は ※にすればよい。
そうでなければデフォルトの動作でよい。
ParaViewのマクロは、importは追加されるが変数は追加無しであるため、execで実行されている訳ではなさそうである。


** yeild [#k1d8f154]

https://qiita.com/weedslayer/items/11de0f314ccbb70de812 ~
returnは関数がそのまま終了する。これに対して、yeildは返値を渡し、制御を戻すが、再度関数が呼ばれると
続きから実行される。
返す値が無くなると、StopIteration例外が発生するようだ。


** printとformat [#n2d42994]

 print( hogehoge, end='' )  #printで改行しない
   end='\t' だと最後にtabが出力
   sep=',' で複数出力する時のセパレータを指定
   file=ファイルオブジェクト でファイルに出力
           fo=open('file.txt', 'w')とし、file=fo とし、使った後で fo.close()
   flush=True で、出力後にフラッシュ

https://note.nkmk.me/python-format-zero-hex/ ~
https://note.nkmk.me/python-numpy-set-printoptions-float-formatter/ ~

 'フォーマット指定の文字列'.format( arg1, arg2, ... )  #フォーマットされた文字列を作る
 '{: >+6,}'.format(+123)  #例 
 formatを使わなくても、
 f'...{argN: >+6,}...' のようにして、同様の文字列を作ることができる
 以上は、print関数と一緒に使う必要は無い。

 {} のところが argNになる
 { や } をそのまま出力する場合には {{ や }} とする
 :  の次が空白だと、余った部分が空白で埋められる。
 +  で正の数でも符号を表示、
 >6 は6文字以下(6文字以上あるとはみ出して表示)
 ,  で3桁ずつ,を付ける
 
 {:10x}      で10桁の16進数表示
 {: >+12.2f} で12文字以下で、小数点以下が2桁で表示
 {: >+12.2e} で同様に指数表現(小数点以下2桁で指数表現)
 {: >+12.2g} で有効数字2桁で表示
 例)
   print('{: >+6,}'.format(+1234567))
   print('{:10x}'.format(+1234567))
   print('{: >+12.2f}'.format(+1234567))
   print('{: >+12.2e}'.format(+1234567))
   print('{: >+12.2g}'.format(+1234567))
   +1,234,567
       12d687
    +1234567.00
      +1.23e+06
       +1.2e+06

 numpyのndarray型のデータをフォーマット指定する場合
   numpy.set_printoptions( formatter={ 'complex_kind' : '{: >+20.4f}'.format } )
   でcomplex128型のデータのndarrayのオブジェクトを出力をすると、
   [     +0.2967-0.4617j      +0.2967-0.4617j]
   などとなる

 __str__メソッドを定義すると、print(インスタンス)で__str__を実行して独自の出力を出せる。
 例)
   class MC:
     def __init__(self,v):
       self.value = v
     def __str__(self):
       return f"MC instance, value = {self.value}"
   
   print( MC(42) )
   MC instance, value = 42


//--------------------------------------------------------------------------------

** クラス変数 [#z81ab08f]

 class Hoge:
    dumm = None         #クラス変数
 
    def __init__( self )
        self.junk = None  #ただのインタンス

 obj1 = Hoge(); obj1.junk = 1
 obj2 = Hoge(); obj2.junk = 2
 obj3 = Hoge(); obj3.junk = 3
 
 Hoge.dumm = 56789
 
 print( Hoge.dumm )
 print( obj3.junk )


//--------------------------------------------------------------------------------

** その他 [#p1bc6d4f]

*** インデントのタブとスペース [#u5078b6f]

 同じスコープのインデントに、タブとスペースが混ざっていたらインデントエラーになる。
 どちらかに統一する。

*** 全角スペースは \u3000 である [#e50b412e]

 a="abc\u3000def"
 b=open( "hoge.txt", "w" ); print(a,file=b); b.close()

*** 文字の置き換え [#t32318a4]

 "AB789CDあEいFG".translate( "".maketrans("あいABC","ai012") )
 これは echo "AB789CDあEいFG" | tr "あいABC" "ai012" のようなものに相当。
 ただし trは日本語不可。

*** 文字列内のパタンを検索 [#i300b42b]

 パタンに一致した場合、その部分を示すre.Matchのオブジェクトを返す。
 reMatchのオブジェクトは、group()によって文字列を受け取れる。
 パタンに一致が無かったらNoneを返す。
 >>> import re
 >>> a=re.search( "\d{4}", "ab12345cd5678ef" )
 >>> a
 <re.Match object; span=(2, 6), match='1234'>
 >>> a.group()  #a=Noneのときは None.group()はエラーになる
 '1234'

 #1行で、エラー込みで、一致した文字列を受け取る(もっとよい方法は?)
 x=re.search( "\d{8}", "ab12345cd5678ef" ); x = x.group() if x else None

https://note.nkmk.me/python-re-match-object-span-group/

*** リストと辞書とsorted [#ecbcce6f]

 >>> d=[ ('A','5'), ('B','4'), ('D','1'), ('C','2'), ('E','3'), ('B','9') ]
 >>> dict(d)
 {'A': '5', 'B': '9', 'D': '1', 'C': '2', 'E': '3'}
 #キーが同じものはひとつのみになる。おそらく最後の要素の値になる

 >>> dict(d).items()
 dict_items([('A', '5'), ('B', '9'), ('D', '1'), ('C', '2'), ('E', '3')])
 #辞書をタプルのリストにしたようなものを与える。see help(dict)

 >>> sorted(dict(d))  #キーのみ並び替えたリストを与える
 ['A', 'B', 'C', 'D', 'E']
 >>> sorted(dict(d).items())  #(キー,値)の並び替えたリストを与える
 [('A', '5'), ('B', '9'), ('C', '2'), ('D', '1'), ('E', '3')]

*** リストとsort [#a8e126d8]

 (注意)
 リストのメッソドsortは データを書き換える。
 組み込み関数のsortedは 新しいリストを生成して与え、元のリストは書き換えない。
 sortは安定な並び替えである。sortedは安定化は不明(helpに無し)。
sortとsortedの違い https://note.nkmk.me/python-list-sort-sorted/

 >>> d=[ ('A','5'), ('B','4'), ('D','1'), ('C','2'), ('E','3'), ('B','9') ]
 >>> d.sort(key=lambda x: x[1], reverse=True)
 >>> d
 [('B', '9'), ('A', '5'), ('B', '4'), ('E', '3'), ('C', '2'), ('D', '1')]

 >>> d=[ ('A','5'), ('B','4'), ('D','1'), ('C','2'), ('E','3'), ('B','9') ]
 >>> d.sort(key=lambda x: x[0], reverse=True)
 >>> d
 [('E', '3'), ('D', '1'), ('C', '2'), ('B', '4'), ('B', '9'), ('A', '5')]

 途中にprint文を挟めた例(なお、stderrに出力させないとキーの値に使われる)
 >>> d=[ ('A','5'), ('B','4'), ('D','1'), ('C','2'), ('E','3'), ('B','9') ]
 >>> d.sort(key=lambda x: (print(x, x[1], file=sys.stderr), x[1]), reverse=True)
 ('A', '5') 5
 ('B', '4') 4
 ('D', '1') 1
 ('C', '2') 2
 ('E', '3') 3
 ('B', '9') 9
 >>> d
 [('B', '9'), ('A', '5'), ('B', '4'), ('E', '3'), ('C', '2'), ('D', '1')]

*** リスト、辞書の整形出力 [#e1df08f7]

 import pprint
 pprint.pprint( list_val, widhth=160 )
https://note.nkmk.me/python-pprint-pretty-print/

*** ファイルをseek [#z9f1b5c5]
 先頭にする例
 fp.seek(0,0)  # offset=0, referencepoint=0 でファイル位置変更


*** 比較演算の組み合わせ [#pa46333c]
 w = 3
 2 <= w and w <= 8
 2 <= w <= 8   #上記と同じ

*** zip [#k45c029a]
 x = ( 1, 2, 3, 4, 5 )
 y = ( 10, 20, 30, 40, 50 )
 for i, j in zip( x, y ):
   print( i, j )

*** 辞書のループ [#j14014dd]
 z = {'a': 1, 'b': 2, 'c':3 }
 for key, val in z.items():
   print( key, val )
 for k in z.keys():
   print( k )
 for v in z.values():
   print( v )


//--------------------------------------------------------------------------------

** Excelのワークブックの読み書き [#qaa96a7d]

 import openpyxl
 wb=openpyxl.load_workbook("testbook.xlsx", data_only=True)
 wksheet=wb["Sheet1"]
 for i in wksheet.iter_rows(min_row=2):
     print( "i=", i, "i[0].row=", i[0].row )
 # 各行のループ変数 iは、excelのセルを要素とするタプルが入っている。
 # i[0], i[1], ..., i[p], ... は左からp番目のセルである。
 # i[p].rowはそのセルがexcelのシートで何行目かの番号である。

 wb = openpyxl.load_workbook( 'sample.xlsx')  #ワークブックの読み込み
 wb = openpyxl.Workbook()  #新規ワークブック生成、

 wb.sheetnames     #シート名のリスト(新規の場合、シートは"Sheet"のみ)
 wb.active         #現在選択されているシート(新規の場合、"Sheet")
 st = wb.active    #現在選択されているシート

 st.title = 'Sheet100'  #シート名変更
 st2 = wb[ st.title ]  #シートの取得
 True if id(st) == id(st2) else False  #Trueが返るのでstとst2は同じもの

 st2[ "D2" ] = "d-2 cell contents"  #セルに代入
 st2.merge_cells( "D3:f4" )         #セルを結合

 st2[ "D3" ] = "combined d-3 cell contents"
 st2[ "D3" ].alignment = openpyxl.styles.alignment\
                         .Alignment( vertical="center" )  #中央配置

 wb.save( "wb-temp.xlsx" )  #ワークブックの保存
https://gammasoft.jp/support/how-to-use-openpyxl-for-excel-file/ ~
https://atmarkit.itmedia.co.jp/ait/articles/2202/08/news031.html ~
https://note.nkmk.me/python-openpyxl-usage/


** csvファイルを読む [#sfe13c9f]

 #csvのフォーマットは生成するソフトに依存しているため注意。Excelの推奨形式は
 #csv.readerで大丈夫らしい。
 import csv
 fp=open( "testbook.csv", encoding='utf-8-sig' )  #BOM付きのファイルの場合
 list( csv.reader( fp ) )
 
 または list(...) の代わりに
 ite=csv.reader( fp )  #_csv.reader関数を返す(イテレータ機能をもつ)
                       #_csvはモジュールらしい。_csvは import _csv;  _csv.__file__
                       #してみると、.soの共有ライブラリのファイルである。
                       #help(_csv); type(_csv); type(_csv).mro() をみよ。
 for r in ite:    #rはcsvの各行のリスト
     for c in r:   #各行について、cは列の項目
         print( c, end=' / ', file=sys.stdout )
     print( file=sys.stdout )

(注) openするとき、BOMがある場合は必ず encoding='utf-8-sig' を指定する。
さもないと、読み込んだ最初の項目の先頭に BOMを示す文字( "\ufeff" )が付いてしまう。
確か、Excelアプリで xlsxから csvを作ると BOM付きである。
BOMなしのファイルは encoding='utf-8-sig' でオープンしても構わないようだ。

https://qiita.com/msk02/items/c3a1c4a1e1ef94c37228 ~
https://www.lifewithpython.com/2017/10/python-detect-bom-in-utf8-file.html

- openのencoding

 fp=open( "testbook.csv" )  #環境に依るが たいていデフォルトで encoding='utf-8'
 fp=open( "testbook.csv", encoding='utf-8' )      #BOMなしファイル
 fp=open( "testbook.csv", encoding='utf-8-sig' )  #BOMつきファイル

- 他

 #- - - - - - - - - - - - - - - - - - - - -
 #ファイルdisp.py
 def disp(ite):
     fo=open( "disp-temp.txt", "w" )  #BOMなしで書き出し
     for r in ite:
         for c in r:
             print( c, end=' / ', file=fo )
         print( file=fo)
     fo.close()
 #- - - - - - - - - - - - - - - - - - - - -
 を作っておいて
 >>> import disp
 >>> disp.disp( ite )  # iteは上のもの
 のように使える。



//--------------------------------------------------------------------------------

* パッケージとモジュールの構造(まとめ) [#t12fefe2]

** 説明の前提(用語、予備知識) [#a2bcf5c7]

次のディレクトリ階層を仮定して、以下を説明。
  mytp
  |-- __init__.py
  |-- mod01.py
  |-- mod02.py
  `-- mysp1
      |-- __init__.py
      |-- mod11.py
      `-- mod12.py
  いま、mod01,02,11,12内に 関数func01,02,11,12があるとする。
  また、インポートのために、mytpを含むディレクトリが PYTHONPATH環境変数などに含まれていること。

- 用語:

パッケージ     = ディレクトリ,     例 mytp

サブパッケージ = サブディレクトリ, 例 mysp1

モジュール     = ファイル,         例 mod01.pyなど


オブジェクト = モジュール、関数、などなど

オブジェクト名は、名前空間でもあり、名前空間には名前空間(オブジェクト)を階層的に含むようだ。
最初に pythonが実行している名前空間は __main__ である。
(__main__で import hoge すると __main__内に hogeの名前空間が作られると思うが、
__main__.hoge のような記述はできないようで、暗黙的に __main__. が付くと思われる。ちょっとちがう?)

名前空間に登録されている名前は dir() で知ることができる。
 __name__                 # 現在の名前空間
 dir( [オブジェクト名] )  # オブジェクト名(名前空間)に登録されている名前(インスタンス名、関数名、
                          # 名前空間名など)のリスト。

//----------------------------
** (トップレベルの) パッケージのインポート [#m67d209d]

 import mytp  # mytp/__init__.pyがあれば実行される。
              # 現在の名前空間に mytpが追加されるが、mytp/__init__.pyが無かったり、空であれば、
              # mytpの名前空間もほぼ空のままであり mytp.mod01などは使用できない。

- モジュールや、モジュール内のオブジェクトのインポート

 import mytp.mod01    # 現在の名前空間にmytpが追加され、mytpの名前空間に mod01が追加され、
                      # mod01モジュールの関数などが使用できる。
 mytp.mod01.func01()

 from mytp import mod01  # mytpディレクトリの mod01が、現在の名前空間に追加される。
                         # mod01モジュールの関数などが使用できる。
 mod01.func01()

 from mytp.mod01 import func01  # mytpディレクトリのmod01内の func01が、現在の名前空間に追加され、
                                # そのままで func01を使用できる。
                        # 追記:func01がモジュールスコープ(今の場合mod01)にて if文を使って条件に
                        #よって defされている関数であってもよいらしい。
 func01()

- mytp/__init__.py を用意すると次のようなことができる

//   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   print( "* __name__ = ", __name__ )  # このパッケージ名 mytp となっている
 
   # __main__で import mytp としただけで mytp.mod01.func01() が使用できるようになる。
   from mytp import mod01  # mytpの名前空間に mod01が追加される。mytp は . でもよいようだ
   from mytp import mod02  # mytpの名前空間に mod01が追加される。mytp は . でもよいようだ
 
   #このファイル ( 名前空間 mytp ) では mod01.func01() が使用できる。
   mod01.func01()
 
   # 関数は名前空間 mytp に登録されるため、 mytp.initmytp() で使用できる。
   def initmypt():
       print( "initmypt" )
//   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

//----------------------------
** サブパッケージのインポート [#a1e00469]

 import mytp.mysp1        # mytp/__init__.pyがあれば実行される。
                          # 現在の名前空間に mytpが追加される。
                          # mytp/mysp1/__init__.pyがあれば実行される。
                          # mytp名前空間に mysp1が追加されるが、mysp1の名前空間はほぼ空であり、
                          # mytp.mysp1.mod11などは使用できない。(状況は import mytp と同じ)。

 from mytp import mysp1   # mytp/__init__.pyがあれば実行される。
                          # mytp/mysp1/__init__.pyがあれば実行される。
                          # 現在の名前空間に mysp1が追加されるが、mysp1の名前空間はほぼ空であり、
                          # mysp1.mod11などは使用できない。(状況は import mytp と同じ)。

- モジュール、モジュール内のオブジェクトのインポート

 import mytp.mysp1.mod11    # mytp/__init__.pyがあれば実行される。
                            # mytp/mysp1/__init__.pyがあれば実行される。
                            # 現在の名前空間にmytpが追加され、mytpの名前空間に mysp1が追加され、
                            # mysp1の名前空間に mod11が追加され、
                            # mod11モジュールの関数などが使用できる。
 mytp.mysp1.mod11.func11()

 from mytp.mysp1 import mod11  # mytp/__init__.pyがあれば実行される。
                               # mytp/mysp1/__init__.pyがあれば実行される。
                               # mytp/mysp1ディレクトリの mod11が、現在の名前空間に追加される。
                               # mod11モジュールの関数などが使用できる。
 mod11.func11()

 from mytp.mysp1.mod11 import func11  # mytp/mysp1ディレクトリのmod11内の func11が、現在の名前空間に追加され、
                                      # そのままで func11を使用できる。
 func11()

- mytp/mysp1/__init__.py を用意すると次のようなことができる

//   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   print( "* __name__ = ", __name__ )  # このパッケージ名+サブパッケージ名 mytp.mysp1 となっている
 
   # __main__で import mytp としてもこのサブパッケージは読み込まれない。
   # import mytp.mysp1 とすると mytp.mysp1.mod11.func11() などが使用できるようになる。
   from mytp.mysp1 import mod11  # mytp.mysp1の名前空間に mod11が追加される。mytp は . でもよいようだ
   from mytp.mysp1 import mod12  # mytp.mysp1の名前空間に mod12が追加される。mytp は . でもよいようだ
 
   # __main__で from mytp import mysp1 とすると mysp1 が名前空間に追加され、mysp1.mod11.func11()など
   # が使用できるようになる。
 
   #このファイル ( 名前空間 mytp.mysp1 ) では mod11.func11() などが使用できる。
   mod11.func11()
 
   # 関数は名前空間 mytp.mysp1 に登録されるため、 mytp.mysp1.initmysp1() で使用できる。
   def initmysp1():
       print( "initmysp1" )
//   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

//----------------------------
** (__main__などからの) パッケージ、サブパッケージの使い方 [#je2cf510]

1) myptや mytp.mysp1をインポートして、mytpからfunc11を指定する。
- 指定が長いが、把握しやすい。
- 混乱しないのであれば asを併用するとよい。

 import mypt
 mypt.mod01.func01()

 import mytp.mysp1
 mytp.mysp1.mod11.func11()

 import mytp.mysp1 as subn
 subn.mod11.func11()

2) mod01や mod11, mysp1をインポートして、mod01や mod11, mysp1からfunc11などを指定する。
- 名前衝突が起こる。
- 把握しにくく、混乱しやすい。

 from mytp import mod01
 mod01.func01()

 from mytp.mysp1 import mod11
 mod11.func11()

 from mytp import mysp1
 mysp1.mod11.func11()


//----------------------------
** その他 __main__.pyなど [#l0c9f01a]

python -m モジュール名  で、モジュールを読み込み。そのモジュールのディレクトリにある 
__main__.pyを実行する(無ければエラー)。
__init__.pyがあれば事前に実行される。

python -m bcone で bcone/__main__.pyを実行させるのがめんどいなら、
alias bcone='python -m bcone' するとよいだろう。
また、__main__.pyで他のファイルを実行したい時は、import bcone.main
とするとよいでしょう(この場合は bcone/main.pyが実行)。

setup.cfg :~
パッケージインストールに関するひとつのファイルである。
中の entry_pointで /usr/bin内に置くコマンドと、そのコマンドにより実行される
パッケージ内のpython関数を指定することができるらしい。
~
setup.py :~
似たようなもの。setuptoolsをimportして使われるようだ。

python -c 'import hoge; hoge.func()' などコードを-cオプションで実行する。importの前に空白があると        
インデントエラーになる。'...'の文字列を改行込みでタイプしても良い。




//----------------------------

//--------------------------------------------------------------------------------

* matplotlibモジュール [#v875f700]

- グラフを描く
-- matplotlib 線・マーカー種類など [[URL>https://science-log.com/pc%E9%96%A2%E9%80%A3/%E3%80%90python%E3%80%91matplotlib%E3%81%A7%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%80%90%E7%B7%8F%E3%81%BE%E3%81%A8%E3%82%81%E3%80%91/#b]]
-- https://qiita.com/nkay/items/d1eb91e33b9d6469ef51

- 3Dグラフを描く
-- https://techacademy.jp/magazine/29976
-- https://dreamer-uma.com/python-3d-graph/
-- https://qiita.com/orange_u/items/8a1e285a45093857aef7




//--------------------------------------------------------------------------------

* numpy, scipyのドキュメント [#ud5a2b2a]

- Numpy and Scipy Documentation https://docs.scipy.org/doc/
-- SciPy search the docs? https://docs.scipy.org/doc/scipy/ reference/
-- SciPy search the docs(正しいURL)? https://docs.scipy.org/doc/scipy/search.html
-- NumPy search the docs  https://numpy.org/doc/stable/





//--------------------------------------------------------------------------------

* scipyモジュール [#n9aeaedb]

** scipy.integrate.RK45クラスの説明 [#cc1f236f]

https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.RK45.html ~
import scipy.integrate; help(scipy.integrate.RK45) も同じ情報が表示される ~
c.f. help(scipy.integrate.solve_ivp)

http://www.physics.okayama-u.ac.jp/~otsuki/lecture/CompPhys2/ode/ode.html ~
//https://www.fixes.pub/program/465196.html ~
RK45は5次のルンゲクッタ法を使用して、4次のルンゲクッタ法のステップサイズを制御している。
また、マニュアル help(solve_ivp) によると、RK45は複素数も利用できる。
ただし、初期値が実数であっても、複素数のデータ型で与えること。





//--------------------------------------------------------------------------------

* numpyモジュール [#x0b905c7]

** ndarray型と matrix型 [#t6f1099c]

 以下は 二次元配列の ndarray型
 ( type(a)でインスタンスの型を調べられる。また、下の float64の 64などは環境依存だろう )
 
 a=numpy.zeros( (2,2) )  # 2行2列のfloat64のゼロで初期化した二次元配列を作る
                         # a.dtypeは float64
 
 a=numpy.array( [[1,2],[3,4]] )  # 組み込みリスト型から、二次元配列を作る
                                 # a.dtypeは int64, リストの要素が整数なので
  
 a=numpy.empty( (2,2) )  # 2行2列のfloat64の未初期化の二次元配列を作る
                         # a.dtypeは float64
 
 a=numpy.array( [[1,2],[3,4]], dtype='complex128')  # dtype指定もできる
                                                    # ビット数を省略するとpythonの組込み型のビット数(環境依存)となる
 b=numpy.zeros_like( a, dtype='float64' )   # aと同じ配列サイズのゼロで初期化した多次元配列を作る
 b[:,:] = 1.2                 #すべての要素を 1.2にする
 b = b.astype( numpy.int64 )  #要素のdtypeをint64に変換する。要素は型変換される

 以下は matrix型(二次元配列に限定され、扱いはndarrayと同じではない)
 
 a=numpy.matrix( [[1,2],[3,4]] )   # 組み込みリスト型から作る
                                   # a.dtypeは int64, リストの要素が整数なので

scipyモジュールは、matrixは使わずに、ndarrayを利用しているようだ。

ndarrayで要素毎に型の違う配列を扱う事も出来るが、その場合には pandasモジュールの方が便利らしい。 

行列の用意、初期化など https://note.nkmk.me/python-numpy-zeros-ones-full/ ~
データ型の指定、など https://note.nkmk.me/python-numpy-dtype-astype/ ~

numpy.ndarray型 https://note.nkmk.me/python-list-array-numpy-ndarray/ ~
二次元配列と行列の演算など https://note.nkmk.me/python-numpy-matrix/ ~


** Python組み込み型変数のビット数を調べる [#v5ef60fe]
 numpy.float_  #らしい。この例は floatについて調べている


** 2次元配列と行列 [#j37d6922]

ndarrayの要素・行などの参照 https://note.nkmk.me/python-numpy-select-element-row-column-array/ ~

 a=numpy.array( [[1,2],[3,4]] ) の2次元配列のとき
 
 a[0,1] や a[0][1] は (0,1)要素
 
 スライスで参照できる、代入もできる
 a[0,:]   は 0行目の1次元配列(次元がひとつ減る)
 a[0:1,:] は 0行目からなる2次元配列
 a[:,0]   は 0列目からなる1次元配列(次元がひとつ減る)
 a[:,0:1] は 0列目からなる2次元配列
 a[:,0] = 9  #参照したすべての要素に 9を代入(右辺が配列の場合、サイズが合うなどすれば代入可)
   次元がひとつ減る => スライスではなく、数字の指定で減る
 
2次元配列や1次元配列を使って行列演算ができる。
numpy.dot関数、 dotメソッド や @ メソッド、で掛算(matrix型の場合は * メソッドも掛算)。
 
なお、2次元配列と1次元配列の掛算では、
1次元配列が、演算の左にある場合は行ベクトル、右にある場合は列ベクトルの2次元配列のように扱われる。
そして、1次元配列同士の掛算は内積になる。

dtype型の違う2次元配列(行列)の演算は、高いほうの型に変換されるようである。(どちらが高い型かの順番は?)


ブーリアンインデックスによる参照、代入も可
 a[ :, (True,True,False,False) ] 

ファンシーインデックスによる参照、代入も可
 a[ :, (0,1) ]   #参照する列の添え字を指定(重複可)、代入も可。

 a > 5       # 配列aの各要素が、条件に対して Trueか Falseかになった配列(ブーリアンインデックス)が返る
 a[ a > 5 ]  # 5より大きい要素のみを指定して参照、代入も可。参照の結果は1次元配列化されて得られる

複数の次元で指定する場合は a[ numpy.ix_( (False,True,True), (True,False,True,False) ) ] のように
ix_関数 を使わないと正しく指定できない。
また、
3次元以上の配列は、ひとつの次元で指定することしか出来ないようである(期待通りの結果にはならないとのこと)。


(※注) 配列がビューではなく、コピーで作られてしまっている場合(生じうる?)は、代入しても値は変化しない



** 多次元配列の次元を減らす [#ba905119]

多次元配列を1次元化する https://note.nkmk.me/python-numpy-ravel-flatten/ ~
多次元配列の次元を減らす https://codechacha.com/ja/python-flatten-list/ ~

 a=numpy.arange(12).reshape( (3, 4) )  # 0~11の要素をもつ 3x4行列
 a.reshape(-1)  # 数字ひとつなので1次元配列。サイズ -1は自動で決められる(この場合は要素数)
 a.ravel()   #可能な限りビューを返す
 a.flatten() #データはビューでは無く、必ずコピーされる
 などなど

多次元配列の形状を変える https://note.nkmk.me/python-numpy-reshape-usage/ ~

 a=numpy.arange(12).reshape( (3,4) )
 a.reshape( (4,3) )  # データはコピーされるが、データの1次元的なメモリー配置変わらなく
                     # サイズが切り直されるような形。
                     # 可能な限りビューが返る。
 a.reshape( (4,3) ).copy()  # 明示的にコピーを返したい場合

 # 引数で、変換順序 order='C' (デフォルト) や 'F' などの指定はできるが、使い道はない?
 # a.reshape( (4,3) ) をそのまま端末に出力した場合と、printで出力した場合で、表示のされ方が異なる。
 # order='C' や order='F' を指定した場合の挙動がよくわからない。

配列の次元、サイズを調べる
 a=numpy.arange(12).reshape( (3, 4) )
 a.ndim
 a.shape


** reshape関数の仕様を調べる [#nc1fe31b]

 import numpy as np
 type( a )  # aが numpy.ndarray のとき
 help( np.ndarray ) # import numpy as np してると、typeで numpy. と出るが、numpy. ではなく np. で指定する
                    # reshapeメソッドの説明はあるが、numpy.reshapeを見よとある
 help( np.reshape )  # 引数newsharpは、intか intのタプルとある


** 注意(viewとcopyを参照) [#u24da219]
 >>> import numpy
 >>> a = numpy.array( [ 1.2, 2.3] )
 >>> b = 2*a
 >>> b
 array([2.4, 4.6])
 >>> a[0] = 7.7
 >>> a
 array([7.7, 2.3])
 >>> b
 array([2.4, 4.6])
 >>> c=b
 >>> c
 array([2.4, 4.6])
 >>> b[0]=9.8
 >>> c
 array([9.8, 4.6]) #ただの代入であればcも変化するので注意!


** ビュー(view)とコピー(copy) [#k5043c15]

https://note.nkmk.me/python-numpy-view-copy-shares-memory/

 a.copy()  #コピーを生成する
 rcd = a.base is None  #Trueなら、ビューである


- numpy.shares_memory( a, b )  #片方がもう一方のビューviewのときTrue

- 引数のデフォルトオブジェクトが共有されてしまう例
 def d( default = {} ):  # defaultの返値 {} が共有されてしまう例
     return default
 av = d()
 au = d()
 av['FOO'] = 100; print( 'av=', av, ' au=', au)
 av['BAR'] = 200; print( 'av=', av, ' au=', au)
 
 def d( default = None ):
     if default == None:
         default = {}  # 共有されない
     return default
 av = d()
 au = d()
 av['FOO'] = 100; print( 'av=', av, ' au=', au)
 av['BAR'] = 200; print( 'av=', av, ' au=', au)
 
 出力結果
 av= {'FOO': 100}  au= {'FOO': 100}
 av= {'FOO': 100, 'BAR': 200}  au= {'FOO': 100, 'BAR': 200}
 av= {'FOO': 100}  au= {}
 av= {'FOO': 100, 'BAR': 200}  au= {}

- pythonの代入等、基本は参照を渡すが、場合によって複製を渡すようだ
 - 深いコピー(deep copy)
 import copy
 hoho = copy.deepcopy( hoge )  #オブジェクトに含まれるオブジェクトも複製する
 単純に、複製である。
 
 - 浅いコピー(shallow copy)
 hoho = hoge  #オブジェクトに含まれるオブジェクトについては参照を渡す
 オブジェクトにオブジェクトが含まれない場合には、深いコピーと同じ。
 
 - 備考
 オブジェクトのcopyメソッドが実際どのようなコピーをするかは、そのクラスに依存すると思われる。
 スライスした次元は、浅いコピーになると思われる。
https://note.nkmk.me/python-copy-deepcopy/


*** mutable(ミュータブル)とimmutable(イミュータブル) [#tb55fdb0]

『オブジェクトによっては 値 を変更することが可能です。
値を変更できるオブジェクトのことを mutable と呼ぶ。
生成後に値を変更できないオブジェクトのことを immutable と呼ぶ。
(mutableなオブジェクトへの参照を格納している immutableなコンテナオブジェクトの値は、
その格納しているオブジェクトの値が変化した時に変化するが、コンテナがどのオブジェクトを
格納しているのかが変化しないのであれば immutableです。
immutable かどうかは値が変更可能かどうかと無関係。)
オブジェクトが mutable かどうかはその型によって決まる』~
[ref] https://docs.python.org/ja/3/reference/datamodel.html から改変

c.f.~
オブジェクトは、同一性(identity)、型、値をもつ。~
id() 関数は同一性を表す整数を返します。~
CPython では、id(x) は x が格納されているメモリ上のアドレスを返す。~
組み込みのデータ型のうち、list, set, dict型のみmutable。~

 def print_id_obj( obj ):
     print( 'id=', id(obj), '  obj=', obj )
 a=1
 b=a
 print_id_obj(a)
 print_id_obj(b)
 print()
 b=2
 print_id_obj(a)
 print_id_obj(b)
//
// #->
// #id= 94427975430944   obj= 1
// #id= 94427975430944   obj= 1
// #
// #id= 94427975430944   obj= 1
// #id= 94427975430976   obj= 2
//
// a=[1,2]
// b=a
// print_id_obj(a)
// print_id_obj(b)
// print()
// b[0]=3
// print_id_obj(a)
// print_id_obj(b)
// print()
// b=[4,5]
// print_id_obj(a)
// print_id_obj(b)
//
// #->
// #id= 47087150371464   obj= [1, 2]
// #id= 47087150371464   obj= [1, 2]
// #
// #id= 47087150371464   obj= [3, 2]
// #id= 47087150371464   obj= [3, 2]
// #
// #id= 47087150371464   obj= [3, 2]
// #id= 47087163414024   obj= [4, 5]






** numpy.stack, hstack, vstack [#jddcdb5f]

 a = numpy.arange(4).reshape( (-1,) ) +100  #[100 101 102 103]
 b = numpy.arange(4).reshape( (-1,) ) +200  #[200 201 202 203]
 
 numpy.hstack( [a,b] )  # [100 101 102 103 200 201 202 203] になる
 
 numpy.vstack( [a,b] )  # [[100 101 102 103]
                        #  [200 201 202 203]] になる

 numpy.stack( [a,b], axis=0 )  # hstackと同じ
 
 numpy.stack( [a,b], axis=1 )  # [[100 200]
                               #  [101 201]
                               #  [102 202]
                               #  [103 203]] になる


** numpy.meshgrid [#h7f8821f]

 ax = numpy.linspace(0,4,5).astype(int)    #[   0    1    2    3    4]
 ay = numpy.linspace(10,14,5).astype(int)  #[  10   11   12   13   14]
 
 x, y = numpy.meshgrid( ax, ay )
 # x
 # [[   0    1    2    3    4]
 #  [   0    1    2    3    4]
 #  [   0    1    2    3    4]
 #  [   0    1    2    3    4]
 #  [   0    1    2    3    4]]
 # y
 # [[  10   10   10   10   10]
 #  [  11   11   11   11   11]
 #  [  12   12   12   12   12]
 #  [  13   13   13   13   13]
 #  [  14   14   14   14   14]]
 
 for j in range(4,0,-1):
     for i in range(0,4,+1):
         print( " {: >2d}-{: >2d}".format(x[j,i], y[j,i]), end="" )
     print()
 #  0-14  1-14  2-14  3-14
 #  0-13  1-13  2-13  3-13
 #  0-12  1-12  2-12  3-12
 #  0-11  1-11  2-11  3-11
 
 xx = x / 2.0
 yy = y / 2.0
 for j in range(4,0,-1):
     for i in range(0,4,+1):
         print( " {: >3.1f}-{: >3.1f}".format(xx[j,i], yy[j,i]), end="" )
     print()
 # 0.0-7.0 0.5-7.0 1.0-7.0 1.5-7.0
 # 0.0-6.5 0.5-6.5 1.0-6.5 1.5-6.5
 # 0.0-6.0 0.5-6.0 1.0-6.0 1.5-6.0
 # 0.0-5.5 0.5-5.5 1.0-5.5 1.5-5.5


** numpy.diff [#fcfc04b7]

 a = np.arange(10).reshape( (-1,) );  b = a*a    # b[i] , i=0~9
 c = numpy.diff( b, n=1 )   # c[i] = b[i+1] - b[i] , i=0~8
 d = numpy.diff( c, n=1 )   # d[i] = c[i+1] - c[i] , i=0~7
 numpy.diff( b, n=2 )       # d[i]と同じ(n回 diffを繰り返す)。二階微分の、中央差分近似に対応


** numpy.where [#z9bb7370]

 a = numpy.arange(10).reshape( (-1,) )
 numpy.where( 5<a, 9.5, 0.5 )    # 配列aの要素が条件( 5< )を満たすとき 9.5、否なら 0.5
 numpy.where( 5<a )              # 条件を満たす要素だけの配列(のタプルが返る)
 numpy.where( 5<a )[0]           # 条件を満たす要素だけの配列






//--------------------------------------------------------------------------------

* mpi4pyモジュール [#g611561b]

 MPIモジュールによる並列化
 importすると、並列実行すると思われる。
 
 comm = MPI.COMM_WORLD



//--------------------------------------------------------------------------------

* anacondaなどによる環境作成 [#s41caa22]

** パッケージ(pythonやモジュール)のインストール方法の種類 [#s5d3fdce]

python自体のインストールと利用バージョン切替

- インストール
-- 各linuxディストリビューションのパッケージ
-- ソースからコンパイル
-- pyenv
-- anacondaの conda

-それぞれ利用するpythonのバージョン切り替え
-- OS側のコマンド
-- pyenv
-- conda

モジュール・パッケージのインストールと使用・不使用切替

-- pipや PyPI(パッケージ管理のみ)( python.orgによる説明 https://packaging.python.org/en/latest/tutorials/installing-packages/ )
-- venv(使用・不使用の環境切替のみ)
-- conda &color(RED){(注)conda環境で、pipは使えるが基本的に使ってはいけない。};

anacondaによる condaコマンドは、
+ 科学計算技術計算のモジュールが豊富(らしい)
+ condaによる環境切替ができる(pythonバージョンやモジュール)

そのため、モジュール間の依存バージョン、依存するpython自体のバージョン、の整合性をとるには condaが楽だろう。
なお、"環境"は、実際には仮想ではないが "仮想環境"と呼ばれている。


** リンク [#u9fff003]

- 参考:パッケージやビルドによる環境
-- CentOS 環境のPython https://www.python.jp/install/centos/index.html

- 参考:anaconda環境
-- Anacondaで仮想環境を作ってみる https://qiita.com/ozaki_physics/items/985188feb92570e5b82d
-- Anacondaを使った仮想環境を保存・再構築、複製 https://qiita.com/ozaki_physics/items/13466d6d1954a0afeb3b
-- condaとpip:混ぜるな危険 https://onoz000.hatenablog.com/entry/2018/02/11/142347 , CondaとPip: https://www.python.jp/install/anaconda/pip_and_conda.html
--- condaとpip:ver.2020 https://onoz000.hatenablog.com/entry/2020/10/24/conda%E3%81%A8pip%3A_ver__2020
--- pip installとconda installの比較 https://chitose-nanase.com/pip-and-conda-install/
-- Anacondaで仮想環境を作るときに役立つTips集 https://cpp-learning.com/anaconda_venv_tips/
-- Anacondaで仮想環境を作ってC++プログラミングをするまで https://cpp-learning.com/anaconda_cpp/
-- Conda コマンド https://www.python.jp/install/anaconda/conda.html
-- パッケージによってはライブラリが必要になる
--- libm (glibc) インストール https://minecraft.server-memo.net/bedrock_server_install/#libm_glibc
--- libffi インストール https://noknow.info/it/os/install_libffi_from_source?lang=ja ,  
https://qiita.com/rabi0102/items/8a749505c78ddc5e4a7d

- 参考:jupyter
-- notebook, lab, hub, lab-hubがある。
-- CentOS7にJupyter Notebookを導入 https://qiita.com/hiroseabook/items/1da01ea439b01c1eb48c
-- CentOS7でJupyter Notebookを簡単インストール・設定 https://qiita.com/y-araki-qiita/items/77c56d266225fe5663a1
-- リモートサーバでJupyter Notebookを実行する方法 https://qiita.com/alchemist/items/ce7f6790bdc2c7cee674
-- (ノードでの使用)Jupyter Notebookの利用 https://docs.abci.ai/ja/tips/jupyter-notebook/
-- JupyterじゃなくてJupyterLabを勧めるN個の理由 https://qiita.com/marutaku0131/items/9881d0430462e655a701
-- JupyterLab-Hubで快適な分析環境を共有しよう! https://qiita.com/atsushi_wagatsuma/items/89b714328663992b54f4
-- 無償で使えるJupyter Notebookオンライン環境 https://www.atmarkit.co.jp/ait/articles/1812/07/news146.html (中央にリンク)
-- JupyterHubを複数ユーザーで使用するための環境構築方法 https://nodaki.hatenablog.com/entry/2019/04/17/220613
-- Jupyter Notebookで分析結果を社内共有!! https://www.optsp.co.jp/news/detail/1080/ (一番下に「数式」入力方法)
-- UbuntuにAnacondaをインストールしてPythonとJupyter Notebookを動かすまでの手順 https://www.virment.com/setup-anaconda-python-jupyter-ubuntu/

- その他
-- 並列計算のパッケージ ipyparallel https://github.com/ipython/ipyparallel
-- ipythonの使い方 https://qiita.com/5t111111/items/7852e13ace6de288042f



//--------------------------------------------------------------------------------

* conda環境の利用方法 [#m726dded]

 conda activate [環境名]  #アクティベート(環境を設定)
 conda deactivate         #デアクティベート(環境を終了)

 conda create -n 環境名 [python[=バージョン] [パッケージ名[=バージョン]] [...]]  #環境作成
 conda remove -n 環境名 --all  #環境の削除

 (補足)
 conda create -n hoge により、インストール場所の/share/apps/anaconda3/{pkgs,envs} 
 や ~/.conda/envs にパッケージや環境が置かれるようだ。
 
 例えば appbinユーザにより /share/apps/anaconda3に anacondaがインストールされているとする。
 シェルコマンド
   eval "$(/share/apps/anaconda3/bin/conda shell.bash hook)"
 により、appbinや他のユーザは conda環境を利用できる。
 
 - appbinユーザにより作成された環境は /share/apps/anaconda3/{pkgs,envs} にファイルが置かれ、
   他のユーザも利用できる。
 
 - 個人のユーザが環境を作った場合には ~/.conda/envs ともともとの /share/apps/anaconda3/pkgs に
   ファイルが置かれて、そのユーザが利用できる。
 - conda create -p pathEnvName により、環境のファイルを置く場所を指定できるため、そのユーザ以外も利用
 できるようにできる、らしい。(/share/apps/envsを指定するなど?)

 (補足2:パッケージの追加インストール)
  各仮想環境へパッケージを追加インストールするには appbinグループを使用して行う。
  (appbinアカウントによるインストールは、誰が入れたか不明になるため非推奨。)
  追加されたパッケージは、他のユーザも利用できるようになる。
  (注1) 依存関係でパッケージのアップデートも必要に応じて行われるため、その場合は
        既存の環境が変更を受ける。アップデートに伴い不具合が出る可能性がある。
        アップデートされたパッケージをすべてアンインストールしてもとに戻すことは
        ほぼ絶望的である。
         環境を壊す危険が高い場合など、検証用にanacondaを別途でインストールをして確認後に、
        パッケージをアップデートするのが望ましい。
  (注2) pipコマンドは /share/app/anaconda3のすべての既存の仮想環境を壊しうるので、使用しない。
        pipを使用した仮想環境は、condaとpipのパッケージの整合性はチェックされないようなので
        不具合が出うる。
         pipでインストールしたパッケージを pipでアンインストールすると、同じパッケージが 
        condaに存在していても利用できなくなるようだ。少なくともpyqt5はそうなった、他の
        仮想環境への影響は今のところ無さそうである。2023/08/09
 
  appbinグループを使用した追加方法は、
  sgコマンドまたはnewgrpコマンドにより、所属グループをappbinに変更後にインストール操作
  をする。手順は以下 1)-3) のいずれか
  1) $ sg appbin bash
     $ インストール作業
     $ exit
  2) $ sg appbin "インストールのためのコマンドライン"  #第3引数は引用符で括る
  3) $ newgrp appbin
     $ インストール作業
     $ exit
  なお、所属グループをappbinに変更し忘れた場合は、
  chown -R :appbin /share/apps/anaconda3 をすればよいようだ(not permittedは多量に出る)。
  (rootユーザが chown -R :appbin /share/apps/anaconda3 をしても同様)
 
  仮想環境の追加作成のときは appbinアカウントを使用する。
  環境は /share/apps/anaconda3/envsに、パッケージは /share/apps/anaconda3/pkgsに入る。
 
  個人ユーザで conda create -n py36 python=3.6 などで仮想環境を作ることもできる。
  この場合、仮想環境は ~/.conda/envsに、パッケージは /share/apps/anaconda3/pkgsに入る。
  そのためこの場合も作成時には appbinグループを使用すること。
 
  個人的にいろいろ試す場合は、個人環境に別途でanacondaをインストールすればよい。


 conda info       #condaの情報
 conda info -e    #環境のリスト
 conda -V         #バージョン
 conda -h         #ヘルプ
 conda config --help     #コマンドconfigのヘルプ
 anaconda search --help  #コマンドsearchのヘルプ
 conda create --help  #コマンドcreateのヘルプ

 conda search [-c チャネル] [--full-name] パッケージ名  #パッケージのバージョンに対応するpythonのバージョン表示
 conda install パッケージ名[=バージョン]    #現在の環境に、パッケージをインストール
 conda uninstall パッケージ名  #現在の環境から、パッケージをアンインストール
 conda list [-n 環境名]                   #インストールされているパッケージのリスト

デフォルト以外のチャンネル: 
https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/channels.html

//? condaが対応していないパッケージのインストールの場合
//?  anaconda search -t conda パッケージ名  #パッケージが対応しているリスト
//?  anaconda show パッケージ名             #チェネルURLなど表示(いずれかの環境がアクティベートされていること)
//  conda install -c チャネルURL パッケージ名

 環境の保存や、それを使った環境作成
  conda env export > ファイル名.yaml
  conda env create -n 新しい環境名 -f ファイル名.yaml
    or
    デフォルトのチャネルだけなら
    conda list --export > ファイル名.txt
    conda create -n 新しい環境名 -f ファイル名.txt

 conda clean --all  #不要なパッケージやキャッシュを削除

 conda create -n 新しい環境名 --clone もとの環境名  #環境名を変更する
 conda remove -n もとの環境名 --all

 conda config --set env_prompt "({default_env}) "  #デフォルトでconda環境のときに付くプロンプトのプレフィックス
 conda config --set env_prompt "p:"                #プロンプトプレフィックスを変更
 
 conda config --set changeps1 false  #プロンプトを変更しない
 echo $CONDA_SHLVL                   #0以外でconda環境であることを確認できる
 
 conda config --set auto_activate_base false  #conda環境に入ったとき自動的にbase環境をactivateしない、たぶん。

 標準的なパッケージをごっそり入れる?
  conda create -n 新しい環境名 [python=バージョン] anaconda

 アップデート
  conda update -n base -c defaults conda   #condaのupdate? base仮想環境もupdateされる?
  conda update conda;conda update anaconda;conda update --all  #conda,anacondaのアップデート?,全パッケージがupdate
 
 アンインストール
  次のものを削除するようだ。
  インストール先のanaconda3 ディレクトリ
  ~/.conda ディレクトリ
  ~/.condarc ファイル
  ~/.bashrcに追加された conda initialize のブロック


*** ハードリンク [#ce9ae41a]
- hoge1, hoge2, hoge3という共通のi-nodeをもつハードリンクのファイルがあったとする。
いずれかのファイルを上書き変更すると、他のファイルもすべて上書き変更された内容になる。
(仮想環境で使われているファイルは、ハードリンクで共通に利用されており、ここに pipで上書きが発生すると
他の全ての仮想環境で意図しないファイルの変更が起こる。)
- emacsで例えば hoge3のファイルを変更・保存したとする。変更された内容は hoge3のみに含まれる。
もともとハードリンクされていたファイルは hoge3~になっている。



*** スクリプトを実行する時だけ conda activateする(通常は OSデフォルトのpythonバージョンが動くままにしておきたい) [#va63ed21]

下記のようなスクリプトを mypyなどとして作っておき、mypy hoge.py などとする。
 #!/bin/bash --norc
 
 #==== set your python env ====
 MYPYTHON=py370
 
 if [ $# == 0 ]; then
    echo "usage: $0 command [args]" >&2
    exit 1
 fi
 
 source /share/apps/anaconda3.bash_conda
 conda activate $MYPYTHON
 
 #==== execute command [args] ====
 "$@"


//--------------------------------------------------------------------------------

* 実行時の symbol lookup error や relocation error の対処 [#n3757fde]

pythonプログラムを実行したときに
symbol lookup error や relocation error が出た場合は、
[[LABO/Rocks]]のページの対処法を見よ。


//--------------------------------------------------------------------------------

* 弘大JupyterHub [#t375c760]
- 弘前大学情報基盤システム(HIROINS) 教育研究事務業務支援システム
-- ログイン https://jupyter01.hirosaki-u.ac.jp:8000/hub/login
--- 裏で動いているCPUは Xeon Gold 5220R 2.20GHz (32コア,第2世代) らしい
-- 実習室パソコンの情報 https://home.hirosaki-u.ac.jp/heroic-2020/


//--------------------------------------------------------------------------------

* Jupyter Notebook [#q450c36b]

** alliumのjupyter notebook [#m5ba35f1]

使用方法は [[LABO/Rocks#tdb7fe60]]を見よ。


** 長い出力部分の表示切替 [#qc798443]
- 長い出力は、スクロールバーが出て部分的に表示される。
-- 左部分をクリックすると、全て表示 ⇔ スクロールバーによる部分表示 の切替が出来る。
-- ダブルクリックすると、非表示になる(クリックで、全て表示にもどる)。

** 括弧などの入力補完(autoCloseBrackets)をオフにする [#y2997562]
 from notebook.services.config import ConfigManager
 c = ConfigManager()
 c.update('notebook',
          {"CodeCell": {"cm_config": {"autoCloseBrackets": False}}})
 を実行して、ノートブックを開きなおす。設定は ~/.jupyter/nbconfig/notebook.json に保存される。

** ipynbをpyに変換する [#u91d1cb0]
 jupyter nbconvert --to python hogehoge.ipynb   #==> hogehoge.pyが作られる


** jupytextを使えるようにする(ipynbとpyの同期) [#mccae438]

デフォルト以外のチャンネル
https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/channels.html
→ https://conda-forge.org/feedstock-outputs/ より conda-forgeにあるパッケージとして
jupytextを検索して https://github.com/conda-forge/jupytext-feedstock を参考に、
 $ conda activate py370
 $ conda install jupytext --channel conda-forge
のようにパッケージをインストールする(/share/apps/anaconda3でインストール済)。

jupyter notebookを起動して hoge.ipynbファイルを開く→ファイル→Jupytext
→Pair Notebook with light Scriptにチェックを入れる。
これで hoge.ipynbと hoge.pyが同期される。
[ref] https://qiita.com/ku_a_i/items/ccdeb7f1d9384fb4767b


** マジックコマンド(%) [#wd5d9a96]

 %matplotlib notebook
 %matplotlib inline
 %time
 など

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS