とぎぷろべい

包丁研ぎとプログラミングと米国株投資についてのなんやかんや

ユーザー定義関数について(Python)

f:id:feci:20210726231508j:plain

Python3

 

Python3.8.5でのユーザー定義関数について。

def abc_def():
  print('xyz100')

abc_def()


#f = abc_def()       #error
f = abc_def
f()
#print(f)            #error
#print(f())          #None

ユーザー定義関数とは、ビルトイン関数ではない関数をdef文を使って自作することです。

ユーザー定義関数は自作関数とも呼ばれます。

 

ユーザー定義関数以外の、あらかじめPythonに用意されている関数はすべてビルトイン関数と呼ばれます。

ビルトイン関数は、組み込み関数やライブラリ関数とも呼ばれます。

 

 

Pythonでのユーザー定義関数は以下の定形によって記述します。

 

def 関数名():
  処理の内容 

 

また、定義した関数を変数に格納してそれを表示することも可能です。

コメントアウトしているパターンは、すべてエラーか値がない状態になります。

 

 

ユーザー定義関数の戻り値について

def aaa():
  a = 'あいうえお'
  return a

result = aaa()
#result()            #error
print(result)

関数で処理した値を戻り値として変数に入れることもできます。

 

その場合は、関数内の処理の後にreturnを記述します。

上記のプログラムでは、関数aaa内で宣言した変数aに入っている値を変数result内に戻り値として格納しています。

 

上記のプログラムの出力結果は、「あいうえお」となります。

 

 

ユーザー定義関数の引数について

def bbb(tomato):
  print(tomato)

bbb('トマト')

関数内で処理する値を外部から引数として入れることもできます。

 

上記のプログラムのように、関数定義をしたあとでその関数内に外部から値を入れることも可能です。

上記のプログラムの出力結果は、「トマト」となります。

 

 

ユーザー定義関数の戻り値と引数を組み合わせたパターンについて。

def ccc(apple):
  if apple == '赤':
    return 'これはりんごです。'
  elif apple == '紫':
    return 'それはぶどうです。'
  elif apple == '黄':
    return 'それはバナナです。'
  else:
    return 'すみませんわかりません。'

result2 = ccc('赤')
result3 = ccc('紫')
result4 = ccc('黄')
result5 = ccc('ルージュ')

print(result2)
print(result3)
print(result4)
print(result5)

 

上記のプログラムは、今まで見てきた関数定義の複数のパターンをミックスして作られています。

関数cccのappleの値を外部から引数として指定してやり、その引数に応じた戻り値をreturnで戻り値として返す、というプログラムです。

 

 

このプログラムの出力結果は、それぞれ以下のようになります。

 

result2の出力結果

これはりんごです。

 

result3の出力結果

それはぶどうです。

 

result4の出力結果

それはバナナです。

 

result5の出力結果

すみませんわかりません。

 

 

関数の引数と戻り値の宣言について。

def num(a:int , b:int) -> int:
  return a + b

r = num(1020)
print(r)        #30

 

関数宣言をするときに、引数と戻り値(返り値)のデータ型を指定することもできます。 

上のプログラムの num(a:int , b:int) の部分で、引数のデータ型をInteger型(整数型)として指定しています。

 

戻り値のデータ型の指定は、-> int: の部分でおこなっています。

この記述により、変数rへreturnされた戻り値のデータ型はInteger型となります。

 

しかし、もし r = num(10,20) の引数を指定している部分に数値ではなくaやbなどの文字列を入力した場合は、当然ですが引数も戻り値もInteger型としては処理されません。

aやbなどの文字列はString型(文字列型)として処理されます。

 

逆に、もし上記のプログラムのintの部分をすべてstrに変えたとしても、引数が半角数字の10と20のままであれば、変数rに格納される戻り値のデータ型はString型ではなくInteger型となります。

そして当然、この場合のrに格納される値は1020ではなく30となります。

 

 

引数の種類について(位置引数、キーワード引数、デフォルト引数)。

#①位置引数
def menu(fooddrinkdessert):
  print('お食事は 'food' です。')
  print('飲み物は 'drink' です。')
  print('デザートは 'dessert' です。')

menu('ステーキ''杏仁豆腐''ビール')


#②キーワード引数
def menu(fooddrinkdessert):
  print('お食事は 'food' です。')
  print('飲み物は 'drink' です。')
  print('デザートは 'dessert' です。')

menu(food='ステーキ'dessert='杏仁豆腐'drink='ビール')


#③デフォルト引数
def menu(food='ステーキ'drink='黒ウーロン茶'dessert='ジェラート'):
  print('お食事は 'food' です。')
  print('飲み物は 'drink' です。')
  print('デザートは 'dessert' です。')

menu(dessert=''drink='ビール')

関数における引数には位置引数、キーワード引数、デフォルト引数の3種類があります。

 

 

このプログラムの出力結果は、それぞれ以下のようになります。

 

①の出力結果

お食事は ステーキ です。
飲み物は 杏仁豆腐 です。
デザートは ビール です。

 

②の出力結果

お食事は ステーキ です。
飲み物は ビール です。
デザートは 杏仁豆腐 です。

 

③の出力結果

お食事は ステーキ です。
飲み物は ビール です。
デザートは です。

 

 

位置引数は引数を記述した位置に対応しています。

①のプログラムは位置引数ですが、もしmenu内の各値の順番を変えると、その変更後の順番に合わせた値が引数として処理されます。

 

キーワード引数は、各値にキーワードを指定することで記述位置に関係なく引数を指定する方法です。

②のプログラムでは引数の記述位置は①と同じですが、キーワードを指定することで引数の位置を任意にコントロールしています。

 

デフォルト引数は、最初から関数内の変数に値を入れておく方法です。

③のプログラムではデフォルト引数としてすでにfoodとdrinkとdessertにそれぞれ値が入っています。

 

なので引数として入ったdessertの「なし」という値とdrinkの「ビール」という値は上書きされてしまいますが、位置引数やキーワード引数のないfood内の値はデフォルト引数の「ステーキ」のまま表示されます。

 

 

デフォルト引数の注意点について
はてなブログの仕様で t= の後ろの空のブラケットが表示されていません。ご注意ください。

#①バグにつながるデフォルト引数のパターン
def aaa(xt=):
  t.append(x)
  return t

z = aaa(100)
print(z)
z = aaa(100)
print(z)


#②バグにつながらないデフォルト引数のパターン
def bbb(xt=None):
  if t is None:
    t = 
  t.append(x)
  return t

w = bbb(200)
print(w)
w = bbb(200)
print(w)

Pythonではリストや辞書などの「参照渡し」になるものをデフォルト引数として置いておくことは推奨されていません。

なぜかというと、バグにつながる可能性が高いからです。

 

 

上記のプログラムの出力結果を見てください。

 

①の出力結果

[100]
[100, 100]

 

②の出力結果

[100]
[100]

 

 

ご覧のように、関数aaaのtに空のリストを引数として指定していた場合、2回目にxに100を入れた際の変数zの出力は[100]ではなく[100, 100]となってしまっています。

この挙動がよくバグにつながってしまうようです。

 

なのでこのバグの芽を摘むために、②のようにtのデフォルト引数にはNoneを入れておき、さらにIF文で t is None: t = [] としてやります。

こうすることでtに位置引数やキーワード引数があるときは関数bbbは通常の挙動になりますし、引数なしのNoneの場合はその都度空のリストが生成されるので、①のような重複バグにはつながらないという状況を作り出せます。

 

 

位置引数のタプル化について。

#①位置引数
def aaa(onetwothree):
  print(one)
  print(two)
  print(three)

aaa('いち''に''さん')


#②位置引数をタプル化したパターン
def bbb(*args):
  print(args)

bbb('いち''に''さん')


#③位置引数をタプル化してfor文でループさせたパターン
def ccc(*args1):
  for arg in args1:
    print(arg)

ccc('いち''に''さん''し''ご')


#④位置引数の一部だけをタプル化するパターン
def ddd(four*args2):
  print(four)
  for arg1 in args2:
    print(arg1)

ddd('いち''に''さん''し''ご')


#⑤引数となる値を事前にタプル化するパターン
def eee(five*args3):
  print(five)
  for arg2 in args3:
    print(arg2)

t = ('に''さん''し''ご')
eee('いち'*t)

 

上記のプログラムのように、位置引数の一部またはすべてをタプル化することもできます。

値をタプル化するには、その値が格納されている変数の頭にアスタリスクをつける必要があります。

 

 

上記のプログラムの出力結果は、それぞれ以下のようになります。

 

①の出力結果

いち

さん

 

②の出力結果

('いち', 'に', 'さん')

 

③の出力結果

いち

さん

 

④の出力結果

いち

さん

 

⑤の出力結果 

いち

さん

 

 

上記のように、位置引数のタプル化は引数の一部またはすべてに引数に対して適応できます。

また⑤のパターンのように、引数になる前に事前に値をタプル化しておくことも可能です。

 

しかし⑤のようなタプル化のパターンは、現在ではあまり使用されていません。

 

また位置引数をタプル化する場合の変数名は、argsを使うのが慣習となっているようです。

 

 

キーワード引数の辞書化について。

#①キーワード引数
def menu(food='お寿司' , drink='八海山'):
  print(food , 'と' , drink)

menu(food='ステーキ' , drink='ビール')


#②キーワード引数の辞書化
def menu(**kwargs):
  for fd in kwargs.items():
    print(f , d)

menu(food='シチュー' , drink='赤ワイン')


#③事前に辞書化した値をキーワード引数として使う
def menu(**kwargs):
  for kv in kwargs.items():
    print(k , v)

x = {
  'food''ラーメン',
  'drink''水',
  'dessert''ごま団子'
}

menu(**x)


#④位置引数、位置引数のタプル化、キーワード引数の組み合わせ処理
def menu(food , *args , **kwargs):
  print(food)
  print(args)
  print(kwargs)

menu('お寿司' , 'ステーキ' , 'ラーメン' , drink='八海山' , dessert='ごま団子')


#⑤*と**の記述順序を間違えた場合
def menu(food , **kwargs , *args):
  print(food)
  print(args)
  print(kwargs)

menu('お寿司' , 'ステーキ' , 'ラーメン' , drink='八海山' , dessert='ごま団子')

キーワード引数は、変数の頭にアスタリスクを2つ付けることで値を辞書化することができます。

 

 

上記のプログラムの出力結果は、それぞれ以下のようになります。

 

①の出力結果

ステーキ と ビール

 

②の出力結果

food シチュー
drink 赤ワイン

 

③の出力結果

food ラーメン
drink 水
dessert ごま団子

 

④の出力結果

お寿司
('ステーキ', 'ラーメン')
{'drink': '八海山', 'dessert': 'ごま団子'}

 

⑤の出力結果

エラー

 

 

キーワード引数の辞書化では、③のパターンのように関数の引数になる前に事前に値を辞書化しておく、ということもよくあるようです。

 

また④のパターンのように、複数の種類の引数を同じ関数内で同時にあつかうということも可能です。

ただこの場合は、*と**の記述順序に注意する必要があります。

 

⑤のパターンのようにタプル化位置引数と辞書化キーワード引数を記述する順序が逆になってしまうと、Pythonはエラーを吐いてしまいます。

 

またPythonでは、位置引数をタプル化する場合の変数名はkwargsを使うのが慣習となっているようです。

 

 

以上です。