Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pythonからみる多相の話

 Pythonからみる多相の話

PyCon mini Hiroshima 2016 の発表資料の一部

出てくるコードのソースコード
https://gist.github.com/eiel/089b705820ce1c83de22440a3252029d

Tomohiko Himura

November 11, 2016
Tweet

More Decks by Tomohiko Himura

Other Decks in Programming

Transcript

  1. from __future__ import print_function class Hello: def say(self): print("Hello") class

    Goodbye: def say(self): print("Goodbye") 2つのクラスがあるとします sayメソッドを持つ
  2. from __future__ import print_function class Hello: def say(self): print("Hello") class

    Goodbye: def say(self): print("Goodbye") selfがHelloの時の処理 selfがGoodbyeの時の処理 HelloクラスとGoodbyeクラスは 別のファイルにあっても良い
  3. from __future__ import print_function class Hello: pass class Goodbye: pass

    class Teacher: def __init__(self, name): self.name = name class Friend: def __init__(self, name): self.name = name
  4. say(Hello(), Teacher("ʹΌΜ͜")) # ͜Μʹͪ͸ɺʹΌΜ͜ઌੜ say(Hello(), Friend("ϞϯςΟ")) # ΍͋ ϞϯςΟ say(Goodbye(),

    Teacher("ʹΌΜ͜")) # ʹΌΜ͜ઌੜɺ͞Α͏ͳΒ say(Goodbye(), Friend("ϞϯςΟ")) # ·ͨͶ ϞϯςΟ
  5. def say(self, target): if isinstance(self, Hello): if isinstance(target, Teacher): print("͜Μʹͪ͸ɻ%sઌੜ"

    % target.name) elif isinstance(target, Friend): print("΍͋ %s" % target.name) elif isinstance(self, Goodbye): if isinstance(target, Teacher): print("%sઌੜɺ͞Α͏ͳΒ" % target.name) elif isinstance(target, Friend): print("·ͨͶ %s" % target.name)
  6. // ݺͼग़ͨ͢ΊͷΠϯλʔϑΣΠε
 trait Say[A, B] {
 def say(a: A, b:

    B): Unit
 }
 
 // ෼ذΛࣗಈੜ੒͢ΔͨΊͷ৔ॴ
 object Say{
 def say[A, B](a: A, b: B)(implicit obj: Say[A, B]) = {
 obj.say(a,b)
 }
 }
  7. // ࣮ࡍͷಈ࡞
 object SayOps {
 implicit val helloTeacherSay: Say[Hello, Teacher]

    = new Say[Hello, Teacher] {
 def say(self: Hello, target: Teacher): Unit = {
 println(s"͓͸Α͏͍͟͝·͢ɻ${target.name}ઌੜ")
 }
 }
 
 implicit val helloFriedSay: Say[Hello, Friend] = new Say[Hello, Friend] {
 def say(self: Hello, target: Friend): Unit = {
 println(s"΍͋ ${target.name}")
 }
 }
 
 implicit val goodbyeTeacherSay: Say[Goodbye, Teacher] = new Say[Goodbye, Teacher] {
 def say(self: Goodbye, target: Teacher): Unit = {
 println(s"${target.name}ઌੜɺ͞Α͏ͳΒ")
 }
 }
 
 implicit val goodbyeFriendSay: Say[Goodbye, Friend] = new Say[Goodbye, Friend] {
 def say(self: Goodbye, target: Friend): Unit = {
 println(s"·ͨͶ ${target.name}")
 }
 }
 } 分岐後の処理が独立しているのがポイント (ifなどの分岐の中にない)
  8. // ࣮ࡍʹಈ͔͢෦෼ object Main extends App {
 import Say.say
 import

    SayOps._
 
 say(Hello(), Teacher("ʹΌΜ͜")) // ͜Μʹͪ͸ɻʹΌΜ͜ઌੜ
 say(Hello(), Friend("ϞϯςΟ")) // ΍͋ ϞϯςΟ
 say(Goodbye(), Teacher("ʹΌΜ͜")) // ʹΌΜ͜ઌੜɺ͞Α͏ͳΒ
 say(Goodbye(), Friend("ϞϯςΟ")) // ·ͨͶ ϞϯςΟ
 }

  9. case class Hello()
 case class Goodbye()
 case class Teacher(name: String)


    case class Friend(name: String) A 分岐の要素となるデータの種類の定義
  10. // ݺͼग़ͨ͢ΊͷΠϯλʔϑΣΠε
 trait Say[A, B] {
 def say(a: A, b:

    B): Unit
 }
 
 // ෼ذΛࣗಈੜ੒͢ΔͨΊͷ৔ॴ
 object Say{
 def say[A, B](a: A, b: B)(implicit obj: Say[A, B]) = {
 obj.say(a,b)
 }
 } B インターフェイスの定義 C 分岐が自動生成される部分
  11. // ࣮ࡍͷಈ࡞
 object SayOps {
 implicit val helloTeacherSay: Say[Hello, Teacher]

    = new Say[Hello, Teacher] {
 def say(self: Hello, target: Teacher): Unit = {
 println(s"͓͸Α͏͍͟͝·͢ɻ${target.name}ઌੜ")
 }
 }
 
 implicit val helloFriedSay: Say[Hello, Friend] = new Say[Hello, Friend] {
 def say(self: Hello, target: Friend): Unit = {
 println(s"΍͋ ${target.name}")
 }
 }
 
 implicit val goodbyeTeacherSay: Say[Goodbye, Teacher] = new Say[Goodbye, Teacher] {
 def say(self: Goodbye, target: Teacher): Unit = {
 println(s"${target.name}ઌੜɺ͞Α͏ͳΒ")
 }
 }
 
 implicit val goodbyeFriendSay: Say[Goodbye, Friend] = new Say[Goodbye, Friend] {
 def say(self: Goodbye, target: Friend): Unit = {
 println(s"·ͨͶ ${target.name}")
 }
 }
 } D 動作を実装する部分
  12. // ࣮ࡍʹಈ͔͢෦෼ object Main extends App {
 import Say.say
 import

    SayOps._
 
 say(Hello(), Teacher("ʹΌΜ͜")) // ͜Μʹͪ͸ɻʹΌΜ͜ઌੜ
 say(Hello(), Friend("ϞϯςΟ")) // ΍͋ ϞϯςΟ
 say(Goodbye(), Teacher("ʹΌΜ͜")) // ʹΌΜ͜ઌੜɺ͞Α͏ͳΒ
 say(Goodbye(), Friend("ϞϯςΟ")) // ·ͨͶ ϞϯςΟ
 }
 E 使う部分
  13. {-# LANGUAGE MultiParamTypeClasses #-}
 import Text.Printf
 
 data Hello =

    Hello
 data Goodbye = Goodbye
 data Teacher = Teacher String
 data Friend = Friend String A 分岐の要素となるデータの種類の定義 おまじない
  14. 
 class Say a b where
 say :: a ->

    b -> IO ()
 B インターフェイスの定義
  15. instance Say Hello Teacher where
 say _ (Teacher name) =

    printf "͜Μʹͪ͸ɻ%sઌੜ\n" name
 
 instance Say Hello Friend where
 say _ (Friend name) = printf "΍͋ %s\n" name
 
 instance Say Goodbye Teacher where
 say _ (Teacher name) = printf "%sઌੜɺ͞Α͏ͳΒ\n" name
 
 instance Say Goodbye Friend where
 say _ (Friend name) = printf "·ͨͶ %s\n" name D 動作を実装する部分
  16. main = do
 say Hello (Teacher "ʹΌΜ͜")
 say Hello (Friend

    "ϞϯςΟ")
 say Goodbye (Teacher "ʹΌΜ͜")
 say Goodbye (Friend "ϞϯςΟ") E 使う部分
  17. class HelloTeacher: def __init__(self, name): self.name = name def say(self):

    print("͜Μʹͪ͸ɻ%sઌੜ" % self.name) class HelloFriend: def __init__(self, name): self.name = name def say(self): print("΍͋ %s" % self.name) class GoodbyeTeacher: def __init__(self, name): self.name = name def say(self): print("%sઌੜɺ͞Α͏ͳΒ" % self.name) class GoodeByeFriend: def __init__(self, name): self.name = name def say(self): print("·ͨͶ %s" % self.name) A 分岐の要素となるデータの種類の定義 D 動作を実装する部分
  18. σʔλ ΠϯλʔϑΣΠε ੜ੒Օॴ ࣮૷ 1ZUIPO ඞཁ μοΫλΠϐϯά Ͱෆཁ ඞཁ ඞཁ

    4DBMB ඞཁ ඞཁ ඞཁ ඞཁ )BTLFMM ඞཁ ඞཁ ෆཁ ඞཁ