PHPしか知らない僕がPythonを少し触ってみたよ 〜関数を作ろう〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
Def Techって今何してるのかな?

この記事を三行にまとめると

関数は「function」ではなく「def」と書きます
その名もダブルアスタリスク!
キーワード引数も便利かなーと思いました
今日は関数を使ってみましょう。基本的にはPHPと同じ要領で使えるのでそんなに難しいことはないと思うんですが、若干PHPにはない概念もあるので、その辺を中心に見ていけたら良いかなと思います。



基本のパターン

とはいえ、まずはシンプルに引数に与えた文字を表示する関数を作ってみます。PHPとPythonでほとんど書き方は一緒です。

PHPの場合はこうですね。

function output($out) {
  echo $out;
}

output('あかつきのお宿');

これで「あかつきのお宿」が出力されます。

同じことをPythonでやるとこうなります。

def output(out) :
  print(out)

output('あかつきのお宿')

Pythonの場合、関数は「function」ではなく「def」と書きます。defineの略ですかね。if文やfor文と同じでかっこはつけずにコロンをつけます。あとネストがないとインデントエラーになるか関数の外にあるコードという判定になってしまうのでご注意。

//PHP(エラーにならない)
function output($out) {
echo $out;
}

output('あかつきのお宿');

#Python(エラーになる)
def output(out) :
print(out)

output('あかつきのお宿')

引数に初期値を与えるやり方や関数の中の値を返すやり方はPHPとPythonで全く一緒です。

def output(out = 'あかつきのお宿') :
  return out

out = output()
print(out) #あかつきのお宿



キーワード引数

Pythonにはキーワード引数という概念があります。どういうのかって言うと……実際に見てもらった方が早いすね。

def output(a, b, c) :
  print(a) #1

output(a = 1, b = 2, c = 3)

こういうの。どの引数にどの値を渡すかを関数を呼び出す時に指定できる感じですかね。キーワード引数で値を指定する場合は、順番が一致している必要はありません。

def output(a, b, c) :
  print(a) #3

output(c = 1, b = 2, a = 3)

この場合、意味合いとしては「先頭の引数に1を入れてくれ」ではなく「cという引数に1を入れてくれ」になります。aやbも同様。だからaが引数の何番目にあっても関数側のaには3が入ってくるという動きになります。

キーワードで引数を指定しているので、引数にないキーワードを使用するとエラーになります。

def output(d) :
  print(a)

output(a = 1)



複数の引数を一つの変数にまとめる

PHPにはfunc_get_argsという、関数に渡した引数を配列で取得できる関数があります。

function output($a, $b, $c) {
  $args = func_get_args();
  print_r($args);
}

output(1, 2, 3); //Array ([0] => 1 [1] => 2 [2] => 3)

こんな感じで全部の引数の値が「$args」という変数に配列で入ってきます。関数の方の引数を省略して書いても同じ結果が得られる。

function output() {
  $args = func_get_args();
  print_r($args);
}

output(1, 2, 3);

Pythonでも同じようなことはできますが、PHPのようにそれ用の関数は必要としません。引数の書き方をちょちょっと変えるだけでOK。

def output(*args) :
  print(args)

output(1, 2, 3) #(1, 2, 3)

Pythonの場合は引数にアスタリスク(*)をつけると、その変数の中に引数の値が全部入ってきます。ただしリストではなくタプルという型になる。まあリストと同じような使い方ができるので、「args[0]」で先頭の値を取ったりできます。

def output(*args) :
  print(args[0]) #1が出力される

output(1, 2, 3)

ただしキーワード引数に使うことはできません。

def output(*args) :
  print(args)

output(a = 1, b = 2, c = 3)

この場合はエラーになります。キーワード引数のパターンについては後述します。



アスタリスクの応用編

PHPのfunc_get_args()は全ての引数をまとめることしかできませんが、Pythonのアスタリスクはもうちょい柔軟な使い方ができます。

例えば三つある引数のうち、先頭の引数はargsに含めないみたいな書き方ができる。

def output(a, *args) :
  print(args)

output(1, 2, 3) #(2, 3)

こうすると先頭の引数(a)に1が入り、残りの2、3がargsに入ります。引数を増やせばそれだけargsの中身が減っていく。

#(3)が出力される
def output(a, b, *args) :
  print(args)

output(1, 2, 3)

#空のタプルが出力される
def output(a, b, c, *args) :
  print(args)

output(1, 2, 3)

#TypeErrorになる
def output(a, b, c, d, *args) :
  print(args)

output(1, 2, 3)

引数と渡す値の数が同じ場合はargsの中は空になるだけでエラーにはならないようですが、args以外の引数の方が多いとエラーになります。

あと一つ注意点があって、アスタリスクのある引数を前に持ってくることはできないです。

def output(*args, a) :
  print(args)

output(1, 2, 3)

こうするとエラーになる。たぶん*argsが先頭にある時点で、全ての引数の値がargsに入っちゃうから、aに渡す値がないぞ的なことなんだと思います。



ダブルアスタリスク

アスタリスクにはさらなる応用があります。その名もダブルアスタリスク!……と呼ぶかどうかは知らんけど、アスタリスクを二つつけることで、キーワード引数をディクショナリとして取得することが可能です。

def output(**args) :
  print(args)

output(a = 1, b = 2, c = 3) #{'a':1, 'b':2, 'c':3}

考え方はシングルアスタリスクの時と同じです。特定のキーワードだけ切り出すこともできるし、**argsより後ろに引数を持ってくることはできない。

#aだけargsに含めない
def output(a, **args) :
  print(args)

output(a = 1, b = 2, c = 3) #{'b':2, 'c':3}

#cだけargsに含めない
def output(c, **args) :
  print(args)

output(a = 1, b = 2, c = 3) #{'a':1, 'b':2}

#エラー
def output(**args, a) :
  print(args)

output(a = 1, b = 2, c = 3)

先ほどシングルアスタリスクをキーワード引数に使えないという話をしましたが、逆にダブルはキーワード引数にしか使えません。

def output(**args) :
  print(args)

output(1, 2, 3)

これはエラーになる。



シングルとダブルの合わせ技

シングルアスタリスクとダブルアスタリスクを同時に使うこともできます。

def output(*args, **kwargs) :
  print(args) #(1, 2, 3)
  print(kwargs) #{'a':4, 'b':5, 'c':6}

output(1, 2, 3, a = 4, b = 5, c = 6)

注意点としては、必ずシングルよりもダブルを後に書かなければならないことですかね。ダブルを先に書くとエラーになります。引数の方も、キーワード引数を先に書いちゃうとエラーになります。

def output(**kwargs, *args) :
  print(args)
  print(kwargs)

output(1, 2, 3, a = 4, b = 5, c = 6)

def output(*args, **kwargs) :
  print(args)
  print(kwargs)

output(a = 4, b = 5, c = 6, 1, 2, 3)

この二パターンはいずれもエラーになっちゃいます。

あとこのパターンもエラーです。

def output(a, *args, **kwargs) :
  print(args)
  print(kwargs)

output(1, 2, 3, a = 4, b = 5, c = 6)

シングルとダブルを併用する場合、それ以外の引数をキーワードに指定することはできないみたいです。これ(↓)ならエラーにならない。

def output(d, *args, **kwargs) :
  print(d) #1
  print(args) #(2,3)
  print(kwargs) #{'a':4, 'b':5, 'c':6}

output(1, 2, 3, a = 4, b = 5, c = 6)

dという引数はキーワードにないのでエラーにはならないです。



グローバル変数

Pythonの場合、関数の外にある変数はグローバル変数になるようです。

def output() :
    print(a) #1
    
a = 1
output()

関数の中にある変数をグローバル化する場合は「global」を使います。

def output() :
  global a
  a = 1

output()
print(a)

これはPHPと同じですね。



参照渡し

以前、こんな記事を書いたことがあります。

基本的に参照渡し

この時にも言いましたが、Pythonは基本的に参照渡しです。だから関数に変数を渡した場合、returnで値を受け取らなくても変数の中身は変化する。

def sample(a):
  a[0] = 5

a = [1, 2, 3]
sample(a)

print(a) #[5, 2, 3]






最初はアスタリスクの使い方がよく分からなくて、リストやディクショナリの値を渡す時にはこれをつけなきゃいけないのかと思ったんですが、そういうことではなかったみたいですね。もっと便利な代物でした。

あとキーワード引数も便利かなーと思いました。後から追加する時とか、順番通りに書かなくてもエラーにならないから、初期値を入れとけば不要な引数は省略して書けるメリットがあると思う。

function($a = 1, $b = 2, $c = 3) {}

例えばこんな関数があった時、PHPは$cの値だけ指定したいって時でも$aと$bを書かなきゃいけないけど、Pythonならキーワード引数でcだけ指定すれば良いからね。

何はともあれ、関数の使い方はこれで一応分かったということで、次回はクラスの書き方を見てみたいと思います。



その他のPythonを少し触ってみたの記事はこちら
前書きと索引的な
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください