Help us understand the problem. What is going on with this article?

brainfuckで関数スタイルとクラススタイルの比較

More than 1 year has passed since last update.

@silver801 さんが投稿された「Pythonでbrainfuckインタプリタ(楔形文字も出る)」を拝見しました。

Pythonにはswitch-caseみたいなやつがないのでif-else祭りになりました。if-else節が長くなるときは一般にはdictを使えと言われてるけど、こういうとき(パターンマッチの後にいろいろ処理を書きたいとき)はどうするのがいいんだろうか?

とのことなので、処理を関数化してdictにしてみました。

関数スタイル

import sys

class Brain:
    pass

def inc(brain):
    brain.mem[brain.ptr] += 1

def dec(brain):
    brain.mem[brain.ptr] -= 1

def fore(brain):
    brain.ptr += 1
    if brain.ptr > len(brain.mem):
        print("overflow!")
        sys.exit(1)

def back(brain):
    if brain.ptr == 0:
        print("Can't decrement anymore")
    brain.ptr -= 1

def putc(brain):
    # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")  # no line break

def getc(brain):
    # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))

def begin(brain):
    if brain.mem[brain.ptr] == 0:
        nest = 1
        while nest != 0:
            brain.head += 1
            if brain.head == len(brain.code):
                print("']' is missing")
                sys.exit(1)
            if brain.code[brain.head] == '[':
                nest += 1
            elif brain.code[brain.head] == ']':
                nest -= 1

def end(brain):
    if brain.mem[brain.ptr] != 0:
        nest = 1
        while nest != 0:
            brain.head -= 1
            if brain.head < 0:
                print("'[' is missing")
            if brain.code[brain.head] == ']':
                nest += 1
            elif brain.code[brain.head] == '[':
                nest -= 1

def nop(brain):
    pass  # ignore other symbol

def brainfuck(code, mem_size=30000):
    operations = {
        "+": inc,    # increment the value at the pointer.
        "-": dec,    # decrement the value at the pointer.
        ">": fore,   # increment the pointer.
        "<": back,   # decrement the pointer.
        ".": putc,   # output the value at the  pointer as utf-8 character.
        ",": getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        "[": begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
        "]": end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
    }
    brain = Brain()
    brain.code = code
    brain.mem = [0] * mem_size
    brain.ptr = 0
    brain.head = 0  # (tape reading) head
    while brain.head < len(code):
        operations.get(code[brain.head], nop)(brain)
        brain.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    brainfuck(code)

if __name__ == "__main__":
    main()

データと関数がバラバラに定義されています。
データと関数をまとめてクラスにしてみます。

クラススタイル

import sys

class Brain:


    def inc(self):
        self.mem[self.ptr] += 1

    def dec(self):
        self.mem[self.ptr] -= 1

    def fore(self):
        self.ptr += 1
        if self.ptr > len(self.mem):
            print("overflow!")
            sys.exit(1)

    def back(self):
        if self.ptr == 0:
            print("Can't decrement anymore")
        self.ptr -= 1

    def putc(self):
        # chr: char -> code point
        print(chr(self.mem[self.ptr]), end="")  # no line break

    def getc(self):
        # ord: code point -> char
        self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))

    def begin(self):
        if self.mem[self.ptr] == 0:
            nest = 1
            while nest != 0:
                self.head += 1
                if self.head == len(self.code):
                    print("']' is missing")
                    sys.exit(1)
                if self.code[self.head] == '[':
                    nest += 1
                elif self.code[self.head] == ']':
                    nest -= 1

    def end(self):
        if self.mem[self.ptr] != 0:
            nest = 1
            while nest != 0:
                self.head -= 1
                if self.head < 0:
                    print("'[' is missing")
                if self.code[self.head] == ']':
                    nest += 1
                elif self.code[self.head] == '[':
                    nest -= 1

    def nop(self):
        pass  # ignore other symbol

    def fuck(self, code, mem_size=30000):
        operations = {
            "+": self.inc,    # increment the value at the pointer.
            "-": self.dec,    # decrement the value at the pointer.
            ">": self.fore,   # increment the pointer.
            "<": self.back,   # decrement the pointer.
            "[": self.begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
            "]": self.end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
            ".": self.putc,   # output the value at the  pointer as utf-8 character.
            ",": self.getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        }
        self.code = code
        self.mem = [0] * mem_size
        self.ptr = 0
        self.head = 0
        while self.head < len(code):
            operations.get(code[self.head], self.nop)()
            self.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    Brain().fuck(code)

if __name__ == "__main__":
    main()

比較

横並びにして比較してみましょう。

import sys                                                  import sys

class Brain:                                                class Brain:
    pass                                                    

def inc(brain):                                                 def inc(self):
    brain.mem[brain.ptr] += 1                                       self.mem[self.ptr] += 1

def dec(brain):                                                 def dec(self):
    brain.mem[brain.ptr] -= 1                                       self.mem[self.ptr] -= 1

def fore(brain):                                                def fore(self):
    brain.ptr += 1                                                  self.ptr += 1
    if brain.ptr > len(brain.mem):                                  if self.ptr > len(self.mem):
        print("overflow!")                                              print("overflow!")
        sys.exit(1)                                                     sys.exit(1)

def back(brain):                                                def back(self):
    if brain.ptr == 0:                                              if self.ptr == 0:
        print("Can't decrement anymore")                                print("Can't decrement anymore")
    brain.ptr -= 1                                                  self.ptr -= 1

def putc(brain):                                                def putc(self):
    # chr: char -> code point                                       # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")                        print(chr(self.mem[self.ptr]), end="")

def getc(brain):                                                def getc(self):
    # ord: code point -> char                                       # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))            self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))

def begin(brain):                                               def begin(self):
    if brain.mem[brain.ptr] == 0:                                   if self.mem[self.ptr] == 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head += 1                                                 self.head += 1
            if brain.head == len(brain.code):                               if self.head == len(self.code):
                print("']' is missing")                                         print("']' is missing")
                sys.exit(1)                                                     sys.exit(1)
            if brain.code[brain.head] == '[':                               if self.code[self.head] == '[':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == ']':                             elif self.code[self.head] == ']':
                nest -= 1                                                       nest -= 1

def end(brain):                                                 def end(self):
    if brain.mem[brain.ptr] != 0:                                   if self.mem[self.ptr] != 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head -= 1                                                 self.head -= 1
            if brain.head < 0:                                              if self.head < 0:
                print("'[' is missing")                                         print("'[' is missing")
            if brain.code[brain.head] == ']':                               if self.code[self.head] == ']':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == '[':                             elif self.code[self.head] == '[':
                nest -= 1                                                       nest -= 1

def nop(brain):                                                 def nop(self):
    pass                                                            pass

def brainfuck(code, mem_size=30000):                            def fuck(self, code, mem_size=30000):
    operations = {                                                  operations = {
        "+": inc,                                                       "+": self.inc,    
        "-": dec,                                                       "-": self.dec,    
        ">": fore,                                                      ">": self.fore,   
        "<": back,                                                      "<": self.back,   
        ".": putc,                                                      "[": self.begin,  
        ",": getc,                                                      "]": self.end,    
        "[": begin,                                                     ".": self.putc,   
        "]": end,                                                       ",": self.getc,   
    }                                                               }
    brain = Brain()                                         
    brain.code = code                                               self.code = code
    brain.mem = [0] * mem_size                                      self.mem = [0] * mem_size
    brain.ptr = 0                                                   self.ptr = 0
    brain.head = 0                                                  self.head = 0
    while brain.head < len(code):                                   while self.head < len(code):
        operations.get(code[brain.head], nop)(brain)                    operations.get(code[self.head], self.nop)()
        brain.head += 1                                                 self.head += 1

def main():                                                 def main():
    args = sys.argv                                             args = sys.argv
    if len(args) < 2:                                           if len(args) < 2:
        code = sys.stdin.read()                                     code = sys.stdin.read()
    else:                                                       else:
        path = args[1]                                              path = args[1]
        with open(path) as f:                                       with open(path) as f:
            code = f.read()                                             code = f.read()
    brainfuck(code)                                             Brain().fuck(code)

if __name__ == "__main__":                                  if __name__ == "__main__":
    main()                                                      main()

Brainの中のbrainは自分自身なのでselfという名称にするのが一般的ですが、
brain のままにすれば、ほとんど一緒ですね。

shiracamus
元、低レイヤーエンジニア。 現、サイバーセキュリティ研究者。 使用言語は、C, Lisp, Java, Python, C#, JavaScript/Node.js。 経験アセンブリ言語は Z80, 6502, 6809, 68000, SPARC, PowerPC, ARM, x86/x64。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした