のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

Python 3エンジニア認定 基礎試験の勉強記録:関数の引数編

先週から引き続き、あらためて Python を体系的に勉強してみて学べたことや、メモとして残しておきたいことなどを記載していきます。今回は 関数の引数編 です。

学習のゴールとして、Python 3エンジニア認定 基礎試験 の合格ですが、Python というプログラミング言語の仕様の全てや、試験合格のコツを解説するのではなく、あくまで自分が気づけたことのメモであることはご了承ください!

この試験ですが、先日受験して合格できました! 今回の記事では、Python の学習や試験を受けて合格するまで振返ってみた所感も記述します。


目次


引数のデフォルト値

まず、次のコードをみてみましょう。

a = 1

def hello(x = a):
    return x

a = 2
res = hello()
print(res)

このコードを実行した結果はどうなるでしょうか? 2 と表示される?それとも 1 と表示される?

正解は、1 と表示されます。

a という変数には、最終的に 2 が代入されていて、その後に hello 関数を呼び出しているから 2 が表示されるんじゃないの?と考えてしまうかもしれません。

ただ、コードを最初から順番にみていきましょう。最初は、 a = 1 で a に 1 を代入しています。

次に、hello 関数を定義しています。この定義の段階で、仮引数 x にデフォルト値として 変数の a の値を設定しています。この時の a の値は 1 なので、x には 1が代入されています。

その後、a に 2 を再代入したとしても、hello 関数の仮引数 x の値は変わらないので、hello 関数を引数を設定せずに呼び出した場合は、デフォルトの値 1 が表示されます。

仮引数のデフォルト値が決定するタイミングの理解が重要ですね!


引数の位置とキーワード

次のような関数があったとします。

def print_param(x,y,z):
    print(x,y,z)

この関数に引数を設定して呼び出す方法として、次の a から e のうち 誤っているもの2 つ あります。どれとどれでしょうか?

  1. print_param(1, y=2, z=3)
  2. print_param(1, 2, z=3)
  3. print_param(x=1, y=2, 3)
  4. print_param(x =1, 2, z=3)
  5. print_param(y=2, z=3, x=1)

いかがでしょうか?

どの選択肢も、引数を 3つ指定しています。また、キーワード引数、つまり x=1 と引数の値を指定してるものもありますが、 仮引数名 (x, y, z) を間違えているわけではないですよね。

ただし、キーワード引数と、位置引数1 のように引数の値だけを記載するもの)を混在して使っているものがあります。

この問題を解くための重要なポイントは、キーワード引数の後に位置引数を指定できない というルールです。

  • 選択肢 A では、キーワード引数 は、y=2z=3 ですが、これらは 1 という 位置引数の後 に指定されているので、正しい指定となります。
  • 選択肢 B も、同様ですね。
  • 選択肢 C はどうでしょうか? キーワード引数 x=1y=2 は、位置引数 3 の前に指定されています。これは誤った指定となります。
  • 選択肢 D も、選択肢C と同様で、キーワード引数が 位置引数の前に指定されているので誤りです。
  • 選択肢 E は、位置引数がないので問題ありません。

ということで、誤っている選択肢は、CD となります。


可変長引数

次はメモとして記載しています。仮引数に * をつけることで、複数の値を タプル として受け取ることができます。

def print_as_tapple(*args):
    print(args)
    
print_as_tapple("a","b","c")

このコードを実行すると、次のように a, b, c の値をもつ タプルとして 表示されます。

('a', 'b', 'c')

また、仮引数に ** をつけることで、複数の値を 辞書型 として受け取ることができます。

def print_as_dict(**args):
    print(args)
    
print_as_dict(a="1",b="2",c="3")

このコードを実行すると、次のように 辞書型として 表示されます。

{'a': '1', 'b': '2', 'c': '3'}

引数のアンパック

次のコードをみてみましょう。

def greeting(name):
    print("Hello!" + name)

【A】
greeting(**me)

このコードで、Hello!Alex という結果を得るには、【A】にはどのようなコードを挿入すればいいでしょうか?

次の選択肢の中から 1 つ選択して下さい。

  1. me = "name=Alex"
  2. me = ("name","Alex")
  3. me = {"name" : "Alex"}
  4. me = "["name","Alex"]"

これは、引数のアンパック に関する問題です。コードの 4 行目で greeting 関数の引数にアスタリスクを 2 つつけて **me と指定しています。

これにより、me の辞書型のキーを、キーワード引数の名前として指定して関数に値を渡すことができます。

つまり辞書型を指定する必要があるので、選択肢 C が正解になります。

greeting 関数の仮引数名は name なので、辞書型のキーの名前と一致する必要があります。

選択肢 C では、辞書型のキーは name で、値が Alex です。キーの name は 仮引数名と一致してますよね。

ちなみに、引数が {"name" : "Alex", "address" : "Kyoto"} の場合は、name 以外のキーも含んでいるので、実行時に次のエラーが発生します。

TypeError: greeting() got an unexpected keyword argument 'address'

参考までに、次のコードは問題なく動作して、Hello!John Doe と表示されます。

def greeting_fullname(fname,lname):
    print("Hello!" + fname + " " + lname)

me = {"fname" : "John", "lname" : "Doe"}
greeting_fullname(**me)

勉強開始から合格までの振り返り

さて、3 回にわたり Python 3エンジニア認定 基礎試験の勉強記録を投稿してきました。

振返ってみると、もともとは、「Python を独学ではなく、体系的に学んでスキルを強化したい!」という思いから始めた取組みでした。

これまで、サンプルなどを参考に Python のコードを書く機会は多々ありましたが、わからないことがあれば、その都度、その部分だけ調べるという取り組みをしてきたので、体系的な学習ができていませんでした。

今回、体系的に Python を学習することで、中途半端に理解していた部分(まさにブログに書いてきた部分)を正確に理解することができたので、とても収穫が大きかったと思ってます。

試験については、市販の問題集や Web から利用できる模擬試験を活用して勉強しました。

そこでわからなかった問題や、間違えた問題は、実際にコードを書いてみて動作を確認するようにしました。また、その際、「もし、コードをこう変えたらどうなるだろう?」というアレンジも積極的に行いました。そのアレンジが、このブログで紹介したサンプルコードになっています。

こういった取り組みはけっこう時間はかかりますが、その分、自分の理解をより深めることができす。

試験本番の直前に受けた模擬試験では、自分にとって難しい問題が多く点数が 730 (合格点は 700) とギリギリだったので、「もしかしたら、危ないかな」ともあせりましたが、実際に試験を受けてみると、難易度は模擬試験より低かったように感じました。(あくまで個人の感想です。たまたま自分にとって簡単だった問題が多かっただけかもしれません。)

そのため、20分ほどで試験を終了して、875 点で合格することができました。

合格してホッとしましたが、同時に「これ以降、Python を積極的に勉強するモチベーションを維持できるかな」という懸念も出てきました。

他にも Dive Deep したいプログラミング言語はあるのですが、せっかくなので Python の勉強は継続したいなと思ってます。また何か Python における テーマをみつけて、そのテーマに沿って学んで、ブログに書いていきます!

そして、今回のチャレンジであらためて感じたことは、プログラミングは楽しい! コードを書くのは楽しい! ということです。

いろんな仕事に忙殺されてコードを書くことが少なくなっているのですが、もっと積極的にコードを書きたい!それが楽しい!と気づけたことも大きな収穫でした!

今後もプログラミングして、コードを書くことを楽しみたいです!


/* -----codeの行番号----- */