質問するログイン新規登録

回答編集履歴

3

追記

2019/02/14 06:34

投稿

LouiS0616
LouiS0616

スコア35680

answer CHANGED
@@ -30,4 +30,62 @@
30
30
  >>> func.__defaults__ = 'spam',
31
31
  >>> func()
32
32
  spam
33
+ ```
34
+
35
+ 質問追記を受けて
36
+ ---
37
+ 関数オブジェクトは呼び出された際、不足する引数にデフォルト値が定められていないか調査します。
38
+ そのときにチェックされる帳簿が`__defaults__`及び`__kwdefaults__`です。
39
+
40
+ > 自分が悩んだのは[0].append(42)の[0]でした。
41
+
42
+ `__defaults__`がデフォルト値のタプルだからです。
43
+ ```Python
44
+ >>> def func(arg1=[], arg2=[]):
45
+ ... print(arg1, arg2)
46
+ ...
47
+ >>> func.__defaults__
48
+ ([], [])
49
+ >>> type(func.__defaults__)
50
+ <class 'tuple'>
51
+ >>>
52
+ >>> func.__defaults__[0]
53
+ []
54
+ >>> type(func.__defaults__[0])
55
+ <class 'list'>
56
+ >>>
57
+ >>> func.__defaults__[0].append(42)
58
+ >>> func()
59
+ [42] []
60
+ >>>
61
+ >>> func.__defaults__[1].append(6)
62
+ >>> func()
63
+ [42] [6]
64
+ ```
65
+
66
+ > func.defaults = 'spam',について考えました。おそらくargs=[]の=以降を変更するのではと考え、args='slim'として行ったところ、spamに変更されていたので、=とするとデフォルト値を変更できるのではという結論に自分の中で至りました。
67
+
68
+ その考えで問題無いように思います。
69
+ ただし関数オブジェクトの属性を書き換えているだけなので、決して特殊な文法ではありませんが。
70
+
71
+ > タプルでは('aaa',)というように,が必要だったのを思い出すと=でデフォルト値を変更する時はタプルとしての操作をする(先例のリストの追加をするときの[0]とは別)のかな
72
+
73
+ 単一要素のタプルのリテラルを記述するときは、
74
+ 文法の都合上最後にカンマ(俗称ケツカンマ)を付けなければなりません。
75
+
76
+ カンマを付けないと、計算の順序を操作する括弧と見分けが付かないからです。
77
+
78
+ > func.defaults[0].append(42)のような形式で、辞書を値のない辞書として、0のかわりにNoneを使用してみましたが、エラーでした。
79
+
80
+ やるならこんな感じでしょうか。
81
+ ```Python
82
+ >>> def moji(a, *, b='ow'):
83
+ ... print(a, b, sep='')
84
+ ...
85
+ >>> moji.__kwdefaults__
86
+ {'b': 'ow'}
87
+ >>> moji.__kwdefaults__['b'] = 'ing'
88
+ >>>
89
+ >>> moji('r')
90
+ ring
33
91
  ```

2

追記

2019/02/14 06:34

投稿

LouiS0616
LouiS0616

スコア35680

answer CHANGED
@@ -5,11 +5,13 @@
5
5
  ---
6
6
  なお、デフォルト値は次のように確認できます。
7
7
  ```Python
8
- >>> def func(arg=[]):
8
+ >>> def func(arg='spam', *, kwarg='ham'):
9
9
  ... pass
10
10
  ...
11
11
  >>> func.__defaults__
12
- ([],)
12
+ ('spam',)
13
+ >>> func.__kwdefaults__
14
+ {'kwarg': 'ham'}
13
15
  ```
14
16
 
15
17
  このことからも、**デフォルト値が関数オブジェクトに所有されている**ことが分かります。

1

追記

2019/02/13 05:14

投稿

LouiS0616
LouiS0616

スコア35680

answer CHANGED
@@ -1,3 +1,31 @@
1
1
  > 関数の呼び出しによって、デフォルトの値に対する新しいオブジェクトが作られるのだと予想しがちです。実はそうなりません。デフォルト値は、関数が定義されたときに一度だけ生成されます。この例の辞書のように、そのオブジェクトが変更されたとき、その後の関数の呼び出しは変更後のオブジェクトを参照します。
2
2
 
3
- 引用元: [Python よくある質問 » なぜオブジェクト間でデフォルト値が共有されるのですか?](https://docs.python.jp/3/faq/programming.html#why-are-default-values-shared-between-objects)
3
+ 引用元: [Python よくある質問 » なぜオブジェクト間でデフォルト値が共有されるのですか?](https://docs.python.jp/3/faq/programming.html#why-are-default-values-shared-between-objects)
4
+
5
+ ---
6
+ なお、デフォルト値は次のように確認できます。
7
+ ```Python
8
+ >>> def func(arg=[]):
9
+ ... pass
10
+ ...
11
+ >>> func.__defaults__
12
+ ([],)
13
+ ```
14
+
15
+ このことからも、**デフォルト値が関数オブジェクトに所有されている**ことが分かります。
16
+ なお、次のような不可解な操作も可能です。
17
+ ```Python
18
+ >>> def func(args=[]):
19
+ ... print(args)
20
+ ...
21
+ >>> func()
22
+ []
23
+ >>>
24
+ >>> func.__defaults__[0].append(42)
25
+ >>> func()
26
+ [42]
27
+ >>>
28
+ >>> func.__defaults__ = 'spam',
29
+ >>> func()
30
+ spam
31
+ ```