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

回答編集履歴

3

修正

2018/07/28 08:28

投稿

tachikoma
tachikoma

スコア3601

answer CHANGED
@@ -55,7 +55,8 @@
55
55
  return (self.x ** 2) ** (1/2)
56
56
 
57
57
  A = MyClass(-2)
58
- print(abs(A))
58
+ print(myabs(A)) # 自作のabs
59
+ print(abs(A)) # Python のbuilt-inのabs
59
60
  ```
60
61
 
61
62
  こんな仕組みが用意されている理由の一つとして考えられ得るのは、数学の絶対値`abs`にいろんな定義があるためです。一例を上げると、質問の中にある絶対値の定義は複素数の絶対値の定義と異なります。そうすると、実数なら・・・複素数なら・・・と様々な定義を`abs`関数に埋め込まないと行けなくなってしまい、とても複雑な関数になってしまいかねません。それを避けるための仕組みなのですが、逆に自分でクラスを作らない限りはこの仕組を意識することはないと思います。

2

補足

2018/07/28 08:28

投稿

tachikoma
tachikoma

スコア3601

answer CHANGED
@@ -1,6 +1,6 @@
1
1
  関数を定義するだけならラムダ式でもいいかもしれませんね。
2
2
  ```Python
3
- abs_made = lambda X : X if X > 0 else -X
3
+ abs_made = lambda x : x if x > 0 else -x
4
4
  ```
5
5
 
6
6
 
@@ -14,4 +14,48 @@
14
14
  print(abs(mat)) # ok
15
15
  print(mat.__abs__()) # abs(mat)は実際にはこう動く
16
16
  print(abs_made(mat)) # fail
17
- ```
17
+ ```
18
+
19
+ ----
20
+
21
+ ----
22
+
23
+ ----
24
+
25
+ ----
26
+
27
+ `__abs__`の話はクラスを知らないと難しいので、興味がない限りスルーしてください。と断った上で続けます。
28
+
29
+ `__abs__`は主にbuilt-in関数の`abs`によって呼び出される(オブジェクト固有の)メソッドです。`numpy.ndarray`という行列の型の場合だと、`np.absolute`と同じです。
30
+ [https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.absolute.html]
31
+ (https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.absolute.html)
32
+
33
+ 疑似コードだとこういう順序です。
34
+ ```Python
35
+ def myabs(x):
36
+ try:
37
+ #
38
+ print("試しにx.__abs__()を呼んでみます")
39
+ return x.__abs__()
40
+ except AttributeError:
41
+ # Xが__abs__を実装していない場合
42
+ print("x.__abs__()なんてありませんでしたorz")
43
+ return x if x > 0 else -x
44
+ ```
45
+
46
+ 自前で`x`が`__abs__`を実装したクラスの例は次の通りです。
47
+ ```Python
48
+ class MyClass:
49
+ def __init__(self, x):
50
+ self.x = x
51
+ def __abs__(self):
52
+ # absに呼び出してもらうための関数
53
+ # 試しに違う絶対値を実装してみる
54
+ print(" MyClassの__abs__だよ")
55
+ return (self.x ** 2) ** (1/2)
56
+
57
+ A = MyClass(-2)
58
+ print(abs(A))
59
+ ```
60
+
61
+ こんな仕組みが用意されている理由の一つとして考えられ得るのは、数学の絶対値`abs`にいろんな定義があるためです。一例を上げると、質問の中にある絶対値の定義は複素数の絶対値の定義と異なります。そうすると、実数なら・・・複素数なら・・・と様々な定義を`abs`関数に埋め込まないと行けなくなってしまい、とても複雑な関数になってしまいかねません。それを避けるための仕組みなのですが、逆に自分でクラスを作らない限りはこの仕組を意識することはないと思います。

1

補足

2018/07/28 08:26

投稿

tachikoma
tachikoma

スコア3601

answer CHANGED
@@ -1,4 +1,17 @@
1
1
  関数を定義するだけならラムダ式でもいいかもしれませんね。
2
2
  ```Python
3
3
  abs_made = lambda X : X if X > 0 else -X
4
+ ```
5
+
6
+
7
+ ----
8
+ 補足
9
+
10
+ Pythonのabsは絶対値を計算するまえに対象のオブジェクトが持っている`__abs__`メソッドがあるかを確認しに行きます。numpyの行列を考えるとこのままじゃまずいですし。
11
+ ```
12
+ import numpy as np
13
+ mat = np.array([-1, 1])
14
+ print(abs(mat)) # ok
15
+ print(mat.__abs__()) # abs(mat)は実際にはこう動く
16
+ print(abs_made(mat)) # fail
4
17
  ```