• Pythonの基本
⑩関数

関数(def)はこんな感じ。
def 文を用いて関数(function)を定義することができます。return文には関数の戻り値を指定します。return 文を省略すると関数は None を返します。
def mul( x, y ):
    ret = x * y;
    return ret;

ret = mul( 3, 5 );
print( ret ); => 15
def repeater( message, repeat=3 ):
    for idx in range( repeat ):
        print( message );

repeater('Google') => Google, Google, Google
repeater('Yahoo', repeat=5 ) => Yahoo, Yahoo, Yahoo, Yahoo, Yahoo
*paramsは残りの順序引数を受け取る。
**key_paramsはキーワード付き引数を辞書型で受け取る。
def function( param1, param2, *params, **key_params ):
    print( param1 );
    print( param2 );
    print( params );
    print( key_params );

function( '1', '2', '3', '4', key1='Key1', key2='Key2' );
=>
1
2
('3', '4')
{'key1': 'Key1', 'key2': 'Key2'}

params = ( '3', '4' )
key_params = { 'key1': 'Key1', 'key2': 'Key2' }
function( '1', '2', *params, **key_params );

=>
1
2
('3', '4')
{'key1': 'Key1', 'key2': 'Key2'}
関数は複数の値を返すことが出来る。
def function():
    return( 999, "ZZZ" );

param1, param2 = function();
print( param1, param2 );
=>999 ZZZ
関数定義の冒頭には"""で ドキュメントストリングを記述できます。
def function( x, y ):
    """Function"""
    return( x + y );
グローバル変数(global)はこんな感じ。
関数の外部で定義された変数はグローバル変数として扱われる。関数の中でグローバル変数を参照することはできるが、代入することはできない。代入する場合はglobalで宣言する必要がある。

g_val = 2;  #グローバル変数

def function():
    global g_val;  #global宣言してやれば
    print( g_val );  #参照可能
    g_val += 1;  # 代入もできる。

function();
global宣言せずに関数内でグローバル変数を参照しようとすると、こうなる。
a

globals()でグローバル変数、locals()でローカル変数の一覧を辞書を返却してくれる。
def function():
    for key in globals().keys():
        print( "GLOBAL: %s = %s" % ( key, globals()[ key ] ) );
    for key in locals().keys():
        print( "LOCAL: %s = %s" % ( key, locals()[ key ] ) );

function()
=>
GLOBAL: __name__ = __main__
GLOBAL: __doc__ = None
GLOBAL: __package__ = None
GLOBAL: __loader__ = <class '_frozen_importlib.BuiltinImporter'>
GLOBAL: __spec__ = None
GLOBAL: __annotations__ = {}
GLOBAL: __builtins__ = <module 'builtins' (built-in)>
GLOBAL: __file__ = C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py
GLOBAL: function = <function function at 0x03CBC300>

LOCAL: key = key

ラムダ式(lambda)はこんな感じ。
名前のない小さな関数を作れる。ラムダ式は式なので関数の引数に入れることが出来る。ラムダ式はもちろんラムダ計算から来てるものと思います。ラムダ計算について調べた(前編)とか読むともっとわかります。が、私的にラムダというと、フルメタルパニックに出てくるラムダ・ドライバという虚弦斥力場生成システム(きょげんせきりょくばせいせいシステム)を思い出します。ラムダってなんかカッコいい。さらに余談が続きますが、職場で誰かがrootをrotとtypoしたことをきっかけにrot(回転:ローテート)div(発散:ダイバージェンス)grad(勾配:グラディエント)なんてベクトル計算の話に発展。しかしダイバージェンスと言われても、もはやSTEINS;GATEのダイバージェンスメータぐらいしかパッと出てきません。ナブラ(∇)とかラプラス(∆)とかテンソル積とか、もはや記憶の彼方。こんなんで機械学習とかできるのかね。中学生にも分かるTensorFlow入門 その1 テンソルとはなにかあたりから始めようかと思う今日この頃。
LambdaFunction = lambda x, y: x * y
print(
LambdaFunction( 4, 8 )
=> 32
イテレータ(iterator)はこんな感じ。

イテレータはfor文で使用することができる繰り返し機能を持つオブジェクト。イテレータオブジェクトは__iter__()でnext()メソッドを持つオブジェクトを返却。next()メソッドは次の要素を返却し最後にStopIteration例外を返すようにする。

class IterClass:
    def __init__( this):
        this.data = ( 9, 8, 7, 6, 5 )
        this.index = 0
    def __iter__( this ):
        return this
    def __next__(
this ):
        if this.index < len( this.data ):
           
this.index += 1
            return
this.data[ this.index - 1 ]
        else:
            raise StopIteration

シンプルで良いですね。
for idx in IterClass():
    print( idx );
=> 9 8 7 6 5

上のfor文は、こんな感じの動作をしてるみたい。
it = IterClass().__iter__()
while 1:
    idx = it.__next__()
    try:
        print( idx )
    except StopIteration:
        break

=> 9 8 7 6 5
Traceback (most recent call last):
  File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 25, in <module>
    idx = it.__next__()
  File "C:\Users\
(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 14, in __next__
    raise StopIteration
StopIteration


ジェネレータ(yield)はこんな感じ。
yieldはイテレータを返却するジェネレータを定義する際に用いられる。

まずYieldを使用しない例。
def NonYieldFunction( list ):
    ret = []
    for idx in list:
        ret.append( idx * 5 )
    return ret

for idx in NonYieldFunction( [ 1, 2, 3, 4, 5 ] ):
    print( idx )
=>[ 5, 10, 15, 20, 25 ]
次にYieldによるイテレータを使った例。
def YieldFunction( list ):
    for idx in list:
        yield idx * 5

for idx in YieldFunction( [ 1, 2, 3, 4, 5 ] ):
    print( idx )

=>[ 5, 10, 15, 20, 25 ]

どちらも実行結果は変わらないが、パフォーマンスに差がでます。NonYieldFunction[ 5, 10, 15, 20, 25 ]のリストを返すのに対してYieldFunctionはイテレータオブジェクトを返します。

NonYieldFunctionの場合、関数呼び出し時に10000要素のリストを渡すと、スタックに10000要素のリストが積まれます。YieldFunction(イテレータ)の場合、リストの要素を1つ取っては計算しを繰り返すので、リストの要素1個分のスタックメモリが消費されるだけです。

例えば、巨大なファイルから特定のキーワードを探し出すようなプログラムの場合、Yieldを使わないとまずファイルを全てスタックに読み込む必要がありますが、Yieldを使えば1行ずつスタックに読み込みキーワードを発見したら抜ければ良いので処理が軽いです。

デコレータ(@)はこんな感じ。
関数を実行する前後に特殊な処理を実行したい場合、@デコレータを使うと
下記の例では、exec()関数を UserDecorator でデコレート(装飾)しています。デコレーション関数では、関数実行前に start を、関数実行後に end を出力しています。

def UserDecorator ( function ): # デコレータ関数を定義する
    def wrapper():
        print( "start" ) # 前処理を実行する
        function() # デコレート対象の関数を実行する
        print( "end" ) # 後処理を実行する
    return wrapper

@UserDecorator
def exec():
    print( "exec" )

exec()
=> start exec end
デコレータの活用事例です。調査対象関数functionに@UserDecoratorをつけることで、関数名、引数、戻り値を表示できます。functoolsのwraps()は調査対象関数の関数名、ドキュメントストリング(__doc__)を後で参照するために呼び出します。
def UserDecorator( function ):
    import functools
    @functools.wraps( function )
    def wrapper( *args, **args2 ):
        print( "FunctionName:", function.__name__ )
        print( "Arguments:", args )
        print( "Keywords:", args2 )
        ret = function( *args, **args2 )
        print( "Return:", ret )
        return ret
    return wrapper

@UserDecorator
def function( msg1, msg2, key=1, mode=2 ):
    """function"""
    print( "----", msg1, msg2, "----" )
    return 9999

n = function( "arg1", "arg2", key=1 )
print( n )

print( repr( function ) )
print( function.__doc__ )
=>
FunctionName: function
Arguments: ('arg1', 'arg2')
Keywords: {'key': 1}
---- arg1 arg2 ----
Return: 9999
9999
<function function at 0x0321D540>
function

⑪クラス

クラス(class)はこんな感じ。慣例でクラス名の先頭は大文字にするみたい。
class UserClass:
    """UserClass"""#ドキュメントストリング(後で__doc__で参照できる)
    def __init__(
this): # コンストラクタ
       
this.name = ""

    def getName(
this): # getName()メソッド
        return
this.name

    def setName(
this, name ): # setName()メソッド
       
this.name = name

cls = UserClass()           # クラスのインスタンスを生成
cls.setName("pavement1234") # setName()メソッドをコール
print( cls.getName() )      # getName()メソッドをコール
=>pavement1234
クラス変数・インスタンス変数(attribute)はこんな感じ。
クラスは、インスタンス変数 と クラス変数 を持つことができる。インスタンス変数は【インスタンス.変数名】で表されインスタンス毎に独立の変数である。インスタンス変数はコンストラクタ__init__の中で初期化することが推奨される。
class UserClass:
    def __init__( this ):
        this.name = "" # インスタンス変数

instance1 = UserClass()
instance1.name = "instance 1"
print( instance1.name )
=> instance 1

instance2 = UserClass()
instance2.name = "instance 2"
print( instance2.name )
=> instance 2
クラス変数は【クラス名.変数名】で表され、すべてのインスタンスで共通の変数。
class UserClass:
    PI = 3.14 # クラス変数

print( UserClass.PI ) # 3.14
=> 3.14
クラス変数でインスタンス数をカウントアップする。
class UserClass:
    count = 0 #クラス変数を0に初期化

    def __init__( this ):
        UserClass.count += 1 # クラス変数をカウントアップ

instance1 = UserClass()
instance2 = UserClass()
print( UserClass.count )
=> 2
クラス変数、インスタンス変数は実行中に追加できる。
class EmptyClass:
    pass #空のクラス

instance = EmptyClass()
instance.name = "instance" # インスタンス変数の追加
EmptyClass.PI = 3.14       # クラス変数の追加

print( instance.name );
print( EmptyClass.PI )
=> instance 3.14

インスタンス変数が存在しない場合【インスタンス.変数名】はクラス変数を参照することに注意。
【インスタンス.変数名】に値を代入するとインスタンス変数が生成される。
以降【インスタンス.変数名】でインスタンス変数が参照される。
class UserClass:
    PI = 3.14

instance1 = UserClass()
instance2 = UserClass()
print( instance1.PI ) # 【インスタンス.変数名】を指定したが
                      # インスタンス変数が存在しないのでクラス変数が参照される。
=>3.14
instance1.PI = 3.14159 # インスタンス変数instance1.PIが生成される。
print( instance1.PI ) # インスタンス変数 instance1.PI(3.14159)が参照される
=>3.14159
print( instance2.PI ) # クラス変数 UserClass.PI(3.14) が参照される
=>3.14
Pythonのclassにはprivate、protectedはなく全てpublic。

メソッド(method)はこんな感じ。

クラスが持つ関数はメソッドと呼ばれる。メソッドもpublic。メソッドの第一引数は必ずクラスのインスタンスを指定する。第二引数以降にメソッドの引数を受け取ることが出来る。
class UserClass:
    name = ""
    def setName( this, name ): #第一引数は自分のインスタンス(this)
        this.name = name
    def getName( this ):
        return this.name

instance = UserClass()
instance.setName( "pavement1234" )
print( instance.getName() )
=> pavement1234

アクセス制限(_、__)はこんな感じ。

Pythonはprivate、protectedはサポートされていない。
アンダーバー(_)で始まる変数や関数は外から参照しないという慣習的ルールがある。
アンダーバー2個(__)で始まる変数や関数は参照が制限され、AttributeError例外が発生する。
しかしアンダーバー2個(__)で始まる変数/関数も、_クラス名__変数名/関数名にすればアクセス出来てしまう。
class UserClass:
    def __init__( this ):
        this.name = "pseudonym"
        this._name = "real name"
        this.__name = "indian name"

    def function( this ): print( 'public' )
    def _function( this ): print( 'private' )
    def __function( this ): print( 'secret' )


instance = UserClass()

print( instance.name ) # 参照OK
=>pseudonym
print( instance._name ) # 参照OKだがしない
=>real name
print( instance.__name ) # 参照できない(AttributeError例外)
=>
Traceback (most recent call last):
  File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 15, in <module>
    print( instance.__name ) # 参照できない(AttributeError例外)
AttributeError: 'UserClass' object has no attribute '__name'

print( instance._UserClass__name ) # こうやると参照できる
=>indian name

instance.function() # 参照OK
=>public
instance._function() # 参照OKだがしない
=>private
instance.__function() # 参照できない(AttributeError例外)
=>
Traceback (most recent call last):
  File "C:\Users\
(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 20, in <module>
    instance.__function() # 参照できない(AttributeError例外)
AttributeError: 'UserClass' object has no attribute '__function'

instance._UserClass__function() # こうやると参照できる
=>secret
コンストラクタ(__init__)はこんな感じ。

__init__() メソッドはコンストラクタと呼ばれ、クラスのインスタンスが生成された際に呼び出される。
class UserClass:
    def __init__( this, name ):
        this.name = name
    def getName( this ):
        return this.name

instance = UserClass( "pavement1234" )
print( instance.getName() )
=> pavement1234

デストラクタ(__del__)はこんな感じ。

__del__() メソッドはデストラクタと呼ばれ、クラスのインスタンスが消滅するときに呼び出される。
class UserClass:
    def __init__( this ):
        print( "initialize" )
    def __del__( this ):
        print( "delete" )


instance = UserClass()
=> initialize
del instance
=> delete

文字列化(__str__)はこんな感じ。
__str__() は、インスタンスを暗黙的に文字列に変換する際の変換処理を定義します。要はprint文にインスタンスを入れると__str__で定義した文字列が返ってくるということですね。
class UserClass:
    def __init__( this, name ):
        this.name = name

    def __str__( this ):
        return "I am " + this.name

instance = UserClass( "pavement1234" )
print( instance )
=> I am pavement1234

継承(inheritance)はこんな感じ。

他のオブジェクト指向言語と同様、クラスを継承できる。
下記の例では、ParentClassクラスを継承した、ChildClassというサブクラスを定義した。
サブクラスでは親クラスが持つアトリビュートやメソッドを継承して利用することができる。
class ParentClass:
    def parent( this ):
        print( "Parent" )

class ChildClass( ParentClass ):
    def child( this ):
        print( "Child" )

instance = ChildClass()
instance.parent()
=>Parent
instance.child()
=>Child
サブクラスでは、親クラスのメソッドを上書き(オーバーライド)することができる。
class ParentClass:
    def exec( this ):
        print( "Parent" )

class ChildClass( ParentClass ):
    def exec( this ):
        print( "Child" )

instance = ChildClass()
instance.exec()
=>Child
親クラス(super())はこんな感じ。
super() は 親クラス を参照する。
第一引数にはクラス、第二引数にはインスタンスを指定する。
下記の例では、サブクラスのコンストラクタの中で、親クラスのコンストラクタを呼び出している。
class ParentClass( object ):
    def __init__( this ):
       this.valParent = 10000

class ChildClass(ParentClass):
    def __init__( this ):
        super( ChildClass, this ).__init__()
        this.valChild = 99999

instance = ChildClass()
print( instance.valParent )
=>10000
print( instance.valChild )
=>99999

多重継承はこんな感じ。
Pythonは多重継承をサポートする。
下記ではBlack、White両方を継承するYelloを定義しています。
class Black:
    def functionBlack( self ):
        print( "Black" )
       
class White:
    def functionWhite( self ):
        print( "White" )

class Yello( Black, White ):
    pass

instance = Yello()
instance.functionBlack()
=>Black
instance.functionWhite()
=>White
クラス階層 はこんな感じ。(Python2かもしれない)
object
 +- int
 |   +- bool
 +- long
 +- float
 +- complex
 +- basestring
 |   +- str
 |   +- unicode
 +- list
 +- tuple
 +- dict
 +- file
 +- BaseException
     +- SystemExit
     +- KeyboardInterrupt
     +- GeneratorExit
     +- Exception
         +- StopIteration
         +- StandardError
         |   +- BufferError
         |   +- ArithmeticError
         |   |   +- FloatingPointError
         |   |   +- OverflowError
         |   |   +- ZeroDivisionError
         |   +- AssertionError
         |   +- AttributeError
         |   +- EnvironmentError
         |   |   +- IOError
         |   |   +- OSError
         |   |       +- WindowsError (Windows)
         |   |       +- VMSError (VMS)
         |   +- EOFError
         |   +- ImportError
         |   +- LookupError
         |   |   +- IndexError
         |   |   +- KeyError
         |   +- MemoryError
         |   +- NameError
         |   |   +- UnboundLocalError
         |   +- ReferenceError
         |   +- RuntimeError
         |   |   +- NotImplementedError
         |   +- SyntaxError
         |   |   +- IndentationError
         |   |       +- TabError
         |   +- SystemError
         |   +- TypeError
         |   +- ValueError
         |       +- UnicodeError
         |           +- UnicodeDecodeError
         |           +- UnicodeEncodeError
         |           +- UnicodeTranslateError
         +- Warning
             +- DeprecationWarning
             +- PendingDeprecationWarning
             +- RuntimeWarning
             +- SyntaxWarning
             +- UserWarning
             +- FutureWarning
             +- ImportWarning
             +- UnicodeWarning
             +- BytesWarning


⑫パッケージとモジュール

モジュールはこんな感じ。
1つのスクリプトファイル(*.py)はモジュールとして扱うことができる。
スクリプトファイルから拡張子を除いた名前がモジュール名。
import文にモジュール名を指定すると、モジュールを読み込める。
読み込んだモジュールのクラス、関数、変数は、【モジュール名.識別子】で参照することができる。
(module.py)

def function():
    print( "mod" )
(test.py)

import module
module.function()
=> mod
モジュールの冒頭に"""ドキュメントストリングを記述できる。
# coding: utf-8
"""module"""
(以下略)

パッケージはこんな感じ。
複数のモジュールをまとめてパッケージとして扱うことができる。
パッケージは、__init__.py という名前のファイルを持つフォルダ、
モジュールは .py ファイルである。
__init__.py にはパッケージの初期化処理を記述する。なければ空でよい。

下記の例ではpack1パッケージの中にpack2パッケージがあり、
pack2パッケージの中にmod.pyモジュールが配置されている。
【フォルダ構成】
フォルダpack1
+ファイル__init__.py
フォルダpack2
  ファイル__init__.py
  +ファイルmod.py

インポート文(import)はこんな感じ。
パッケージの中からモジュールや識別子(クラス、関数、変数…)をインポートするには下記の様にする。
# import [パッケージ.]モジュール
import pack1.pack2.mod
pack1.pack2.mod.function()

# from パッケージ import モジュール
from pack1.pack2 import mod
mod.function()

# from パッケージ import *
from pack1.pack2 import * # __all__の設定が必要
mod.function()

# from [パッケージ.]モジュール import 識別子
from pack1.pack2.mod import function
function()

# from [パッケージ.]モジュール import *
from pack1.pack2.mod import *
function()

上記の例で「from パッケージ import *」の形式を用いるには、
pack2 パッケージの __init__.py ファイルに読み込み対象のモジュールリストを__all__ に定義しておく必要がある。


(__init__.py)

__all__
= ["mod"]

読み込むモジュールや識別子を複数記述することもできる。
import pack1.pack2.mod1, pack1.pack2.mod2
from pack1.pack2 import mod, mod2
from pack1.pack2 import ( mod, mod2 )
from pack1.pack2.mod import function1, function2
from pack1.pack2.mod import ( function1, function2 )
読み込んだモジュール名や識別子に別名をつけることができる。
import pack1.pack2.mod as mod1
mod1.function()

from pack1.pack2 import mod as mod2
mod2.function()

from pack1.pack2.mod import function as function1
function1()

from には(.)や(..)や(...)を用いてパッケージを相対的に指示することができる。
from . import mod  # このパッケージから modモジュールをインポートする
from .. import mod  # ひとつ上の階層のパッケージから modモジュールをインポートする
from ... import mod  # ふたつ上の階層のパッケージから modモジュールをインポートする
from ...pack4 import mod  # ふたつ上の階層のpack4パッケージから modモジュールをインポートする

パッケージ名(__package__)はこんな感じ。
__package__ は現在のパッケージ名を示す。
print( __package__ )
=> None
ファイル名(__file__)はこんな感じ。
__file__ は現在のファイル名を示す。
print( __file__ )
=>C:/Users/(ログインユーザ名)/AppData/Local/Programs/Python/Python37-32/test.py
モジュール名(__name__)はこんな感じ。
__name__は現在のモジュール名を示す。スクリプトとして起動したメインモジュールの場合は __main__という名前が設定されている。下記の例はファイルがpythonコマンドから直接起動された場合のみ実行する処理を記載。
if __name__ == "__main__":
    function()
ビルトインモジュール(builtins)はこんな感じ。
builtinsはopen()などのビルトインオブジェクトを包含する仮想的なモジュールを示す。
(test.py)
import builtins
for line in builtins.open( "test.py" ):
    print( line )
=>
import builtins
for line in builtins.open( "test.py" ):
    print( line )

  • 終わりに
久々にプログラミング言語に長時間触れました。Pythonはシンプルでなかなか良いですね。最初はAndroidでチマチマやってましたが、だんだんスマホから打つのが面倒になりWindows版PythonのIDLEをフル活用しました。やはりたくさんコードを打つと、それだけ言語に愛着も沸くし、身にもつくってもんです。来週仕事でPythonコードを読むことになりそうなので、良いリハビリになりました。





全然関係ないけど、八王子セレオにドローンスクールできた。ドローン衝動買いする買う前に、まずはやってみようかな。いつか子供にカッコつけたいし。
IMG_20190608_113456
IMG_20190608_113504





スポンサードリンク