howto/python

コメント

  • pythonでは i++はできないので、i+=1 -- 2021-08-26 (木) 09:46:13
  • numpy.linspace(0,10,5) # 0と10を含む5要素のリスト -- 2021-08-30 (月) 16:22:40
  • デコレータ(@hogehoge) https://qiita.com/mtb_beta/items/d257519b018b8cd0cc2e https://zenn.dev/ryo_kawamata/articles/learn_decorator_in_python -- 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 )
  • イテレータからイテレータを呼んでいる例 -- 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 インスタンス #インスタンスを削除する -- 2021-10-07 (木) 09:54:57
  • a[0][:,0] と a[0][:][0] は違う結果になるようだ。 -- 2021-10-08 (金) 20:07:29
  • ブロードキャスト: たとえば、サイズの異なる配列間の演算に出てくる概念のこと -- 2022-03-13 (日) 19:37:49
  • numpyにloadtxtというのがあり、列ごとにコンバーター converters = {0: datestr2num} などを渡せる。 -- 2022-06-22 (水) 21:17:08
  • クラスについての説明と名前空間の話し(python.org) https://docs.python.org/ja/3/tutorial/classes.html -- 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文の代用 -- 2022-06-28 (火) 11:12:12
  • print(*map(lambda x: '"{}"'.format(x), '日月火水木金土'), sep=',') #個々の文字を引用符 " で括って、*により個々にprintの引数として渡される -- 2022-06-28 (火) 11:19:24
  • フーリエ変換の例 -- 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 -- 2023-08-30 (水) 11:25:47
  • openしたときのストリームインスタンスの型とreadlineメソッド -- 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など) -- 2023-10-13 (金) 17:30:11
  • バイトコンパイル・コンパイル -- 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があると文法エラーになるため、先頭にコードを追加するだけではバージョンチェックはできなさそう。 -- 2024-05-18 (土) 15:39:38 New

ドキュメント

  • 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 )  #説明
  • オブジェクトがどのクラスインスタンスであるかであるか知る(例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]

命名の慣例

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モジュール

(注) 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する

>>> 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)など

いくつかの例

インタプリタ起動

$ 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

#正規表現を使ったファイル一覧の取得
>>> 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']

基本

組み込みデータ型

整数  
浮動小数点  
複素数  
文字列  
リスト  [ 1, 2, 3 ]
タプル  ( 1, 2, 3 )   要素ひとつの場合は ( 1, )とする。( 1 ) = 1 = 整数の値などとなるため
ディクショナリ { k1:v1, k2:v2, k3:v3 }
bytes型  
bool型  
set型  { 1, 2, 3 }
iter  イテレート可能なインスタンスに変換する

備考:
順番があるものが、シーケンス型。
書き換えが可能なものが、書き換え可能型。
書き換え可能でない型は、文字列、タプル(ただし要素追加は可能)と、数値もである(丸ごとの書き換えは可)。
関数の引数は、関数で値を書き換えても、呼び出し元では変わらない(値渡しに相当)。書き換え
可能なものもある(例:リストを渡して、リストの要素を書き換えると呼び出し元でも変更されている)。

型変換

int()  文字列を数値に変換
float() 
str()  
chr()  数値を文字(列)に変換
hext  数値を16進数に変換
bin  数値を2進数に変換
oct  数値を8進数に変換

スライス

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

lambda式

 see Python文法詳細、p197、オライリー

整数除算(商)

i // 2
(iは整数だけでなく、浮動点小数でも切り捨て)

文字列操作

raw文字列  r"C:\path\to\file"
split
join

アンパック代入

 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}" )

リストのアンパック

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

可変長引数

 *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/

ゲッターとセッター(プロパティ)

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

標準エラー出力に書き出す

print( "hoge", file=sys.stderr )

コメント

#comment1
'''
comment2a
'''
"""
comment2b
"""

python環境がらみの情報取得

  • 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

モジュールの検索順
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は一回だけしか評価されない

パッケージ

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

関数の動的呼び出し

モジュール 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インジェクションのようなものに
注意する。

複素数の扱い

https://note.nkmk.me/python-complex/

例外処理

globalとnonlocal

  • 関数内でのグローバル変数の利用
    http://www.ops.dti.ne.jp/ironpython.beginner/global.html
    関数内で、グローバル変数に代入したいとき、関数内でglobal宣言をする。 さもないとエラーになるか、ローカル変数として扱われる。
  • 違い
    global hoge    # hogeはモジュールスコープ(グローバルスコープ)のものであることを宣言
    
    nonlocal hoge  # hogeは外側、無ければ、外側の外側、外側の外側の...のスコープのもの
                   # であることを宣言。
                   # ただし、モジュールスコープのものであることを宣言することはできない
  • 用語: クロージャ=外側のスコープの変数を参照して値を変える関数のこと?

globalsとlocals

それぞれグローバル変数、ローカル変数を表示する。追加も可。

>>> 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

ソースコードを実行する。他のファイルを読み込んで実行するときは 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

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

printとformat

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

その他

インデントのタブとスペース

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

全角スペースは \u3000 である

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

文字の置き換え

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

文字列内のパタンを検索

パタンに一致した場合、その部分を示す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

>>> 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

(注意)
リストのメッソド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')]

リスト、辞書の整形出力

import pprint
pprint.pprint( list_val, widhth=160 )

https://note.nkmk.me/python-pprint-pretty-print/

ファイルをseek

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

比較演算の組み合わせ

w = 3
2 <= w and w <= 8
2 <= w <= 8   #上記と同じ

zip

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

辞書のループ

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のワークブックの読み書き

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ファイルを読む

#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は上のもの
のように使える。

パッケージとモジュールの構造(まとめ)

説明の前提(用語、予備知識)

次のディレクトリ階層を仮定して、以下を説明。

 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( [オブジェクト名] )  # オブジェクト名(名前空間)に登録されている名前(インスタンス名、関数名、
                         # 名前空間名など)のリスト。

(トップレベルの) パッケージのインポート

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" )

サブパッケージのインポート

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__などからの) パッケージ、サブパッケージの使い方

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など

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モジュール

numpy, scipyのドキュメント

scipyモジュール

scipy.integrate.RK45クラスの説明

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
RK45は5次のルンゲクッタ法を使用して、4次のルンゲクッタ法のステップサイズを制御している。 また、マニュアル help(solve_ivp) によると、RK45は複素数も利用できる。 ただし、初期値が実数であっても、複素数のデータ型で与えること。

numpyモジュール

ndarray型と matrix型

以下は 二次元配列の 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組み込み型変数のビット数を調べる

numpy.float_  #らしい。この例は floatについて調べている

2次元配列と行列

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次元以上の配列は、ひとつの次元で指定することしか出来ないようである(期待通りの結果にはならないとのこと)。

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

多次元配列の次元を減らす

多次元配列を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関数の仕様を調べる

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を参照)

>>> 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)

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(イミュータブル)

『オブジェクトによっては 値 を変更することが可能です。 値を変更できるオブジェクトのことを 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)

numpy.stack, hstack, vstack

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

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

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

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モジュール

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

comm = MPI.COMM_WORLD

anacondaなどによる環境作成

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

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

  • インストール
    • 各linuxディストリビューションのパッケージ
    • ソースからコンパイル
    • pyenv
    • anacondaの conda
  • それぞれ利用するpythonのバージョン切り替え
    • OS側のコマンド
    • pyenv
    • conda

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

anacondaによる condaコマンドは、

  1. 科学計算技術計算のモジュールが豊富(らしい)
  2. condaによる環境切替ができる(pythonバージョンやモジュール)

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

リンク

conda環境の利用方法

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 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 のブロック

ハードリンク

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

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

下記のようなスクリプトを 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 の対処

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

弘大JupyterHub

Jupyter Notebook

alliumのjupyter notebook

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

長い出力部分の表示切替

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

括弧などの入力補完(autoCloseBrackets)をオフにする

from notebook.services.config import ConfigManager
c = ConfigManager()
c.update('notebook',
         {"CodeCell": {"cm_config": {"autoCloseBrackets": False}}})
を実行して、ノートブックを開きなおす。設定は ~/.jupyter/nbconfig/notebook.json に保存される。

ipynbをpyに変換する

jupyter nbconvert --to python hogehoge.ipynb   #==> hogehoge.pyが作られる

jupytextを使えるようにする(ipynbとpyの同期)

デフォルト以外のチャンネル https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/channels.htmlhttps://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


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-05-18 (土) 15:41:22 (1d)