毎朝ちびちびCodewars。
Change your Points of View [6級] www.codewars.com
今日のお題:
""" 次の4つの関数を定義する。 point(x, y) は、座標(x, y) の情報を含んだ callable な関数を返す。 def point(x, y): return lambda ... callable(point(3,4)) -> True fst(pt) , snd(pt) は、それぞれ地点(x, y)に対する x, y を返す関数。 lint(pt1, pt2)は、2点間を通る直線の式 ax + by + c = 0 の定数[a, b, c]を返す関数。 例: p0 = point(3, 5) callable(p0) -> True fst(p0) -> 3 snd(p0) -> 5 p1 = point(22, 55), p2 = point(75, 66) sqr-dist(p1, p2) -> 2930 p3 = point(20, 22) p4 = point(29, 10) line(p3, p4) -> [12, 9, -438]
コード
mine
# Change your Points of View # https://www.codewars.com/kata/change-your-points-of-view/ def point(a, b): return lambda : (a, b) def fst(pt): return pt()[0] def snd(pt): return pt()[1] def sqr_dist(pt1, pt2): return (fst(pt2)-fst(pt1))**2 + (snd(pt2) - snd(pt1))**2 def line(pt1, pt2): l = snd(pt1) - snd(pt2) m = fst(pt2) - fst(pt1) n = fst(pt2) * (snd(pt2) - snd(pt1)) - snd(pt2) * (fst(pt2) - fst(pt1)) return [l, m, n]
他ユーザによるエレガントな解
def point(a, b): f = lambda: (a, b) f.x = a f.y = b return f def fst(pt): return pt.x def snd(pt): return pt.y def sqr_dist(pt1, pt2): return (pt2.x-pt1.x) ** 2 + (pt2.y-pt1.y) ** 2 def line(pt1, pt2): a = pt1.y - pt2.y b = pt2.x - pt1.x c = pt1.x*pt2.y - pt2.x*pt1.y return [a, b, c]
point()内で 無名関数のリファレンスを返値で返すところがポイント。
return point
では p1 = point(10, 20) p2 = point(1, 2) とかしたら p1 も p2 も同じになっちゃう。
ちょっとわからなかったのは、point()関数内の f.x, f.yのこと。
point関数のローカル変数ではなさそう。
実際に point関数内で、 locals()を実行すると
{'f': <function point.<locals>.<lambda> at 0x10f933950>, 'b': 3, 'a': 2}
が返り f.x, f.yは含まれてない。
無名関数(ラムダ式)のローカル変数??
point()の外から参照もできれば、書き換えることもできる。
>>> p1 = point(20, 30) >>> print(p1.x) 20 >>> p1.x = 2 >>> print(p1.x) 2
振る舞いとしてはClassで ↓こういう風に書いた時に近いのかな。。。?!
class Point: def __init__(self, a, b): self.x = a self.y = b
なにも関数の中で書かなくてもいいのか。
def point2(a, b): f = lambda: (a, b) return f p = point2(2, 3) p.x = 10 p.y = 20 print(p()) # (2, 3) print(p.x, p.y) # 10 20
文法、関数・メソッドnote
callable(object)
組み込み関数 — Python 3.7.4rc2 ドキュメント
今回のチャレンジのテストケースで使われていた組み込み関数。 objectが呼び出し可能なオブジェクトなら True 、そうでなければ False を返す。 今回の例なら
>>> callable(point) # 関数 True >>> callable(Point) # クラス True >>> callable(p1.x) # p1.xはint型のリテラル False