SlideShare a Scribd company logo
PyConJP 2012




Fantastic DSL
in Python
Makoto Kuwata <kwa@kuwata-lab.com>
http://www.kuwata-lab.com/
2012-09-16 (Sun)

Video: http://www.youtube.com/watch?v=l8ptNmtB0G8
Agenda
•About DSL
•Fantastic 'with' statement
•Fantastic 'for' statement
•Fantastic Decorator
•Fantastic Operator
About DSL
What is DSL (Domain Specific Language?)




         DSL

             Google Search
Internal DSL v.s. External DSL
•Internal DSL (内部DSL)
 •Written inside an existing host language
   既存の言語を使って、その言語の文法を使って書かれたDSL

 •No need to implement parser
   パーサを書く必要なし

 •Some lang are not good at internal DSL
   言語によっては苦手な場合がある

•External DSL (外部DSL)      Python?
 •Original, indendent syntax
   独自の文法

 •Need to implement parser
   パーサを実装する必要あり

 •All languages have same power about external DSL
   言語による得手不得手は、ほぼない
Fantastic 'with' Statement
What is 'with' statement?

•Enforces finishing       ## Python 2.4
 process                 f = open('file')
 終了処理を強制する機能             try:
 •ex: close opened file     text = f.read()
  certainly              finally:
   例:ファイルを必ず閉じる            f.close()

                         ## Python 2.5 or later
                         with open('file') as f:
                          text = f.read()
How to use 'with' statement in DSL?

•Appends pre-
                             Append pre-process
 process and post-                 前処理を追加
 process around

                               }
 block                 x=1
 ブロックに前処理と後処理をくっ
                       y=2         code block
 つける                   z=3

                            Append post-process
                                   後処理を追加
Case Study: Change Directory (Kook)

## before               ## after
chdir('build')          with chdir('build'):
cp('../file', 'file')     cp('../file', 'file')
system('cmd...')          system('cmd...')
chdir('..')
Case Study: Start/Stop time (Benchmarker)

## before              ## after
t1 = time.time()       bm = Benchmarker()
for i in xrange(N):    with bm('func'):
   func()                for i in xrange(N):
t2 = time.time()            func()
print('func: %s'
        % (t2-t1))
Case Study: Form Builder

 ## before
 <form action="/" method="POST">
  <input type="hidden" name="_csrf"
         value="${request.csrf()}" />
  <input type="text" ... />
  <input type="submit" ... />
 </form>
Case Study: Form Builder

 ## after
 % with FormBuilder(request, "/") as fb:
  <input type="text" ... />
  <input type="submit" ... />
 % endwith
Pitfall: Variable Scope

 with test("arithmetic operation"):

    with test("1+1 should be 1"):
      x = 1+1
      assert x == 2

    with test("1-1 should be 0"):
      x = 1-1         Identical variable because
      assert x == 0 scope is not independented
                          スコープが独立してないので変数も共有される
Pitfall: Cannot Skip Block!

 <div>
 % with cache("key", 60*60*1):
   <ul>
   % for item in get_items():
   <li>${item}</li>
   % endfor        You may want to skip block
   </ul>           when cache is not expired,
 % endwith         but Python doesn't allow it!
 </div>            キャッシュが生きている間はブロックを
                      スキップしたいんだけど、実はできない
Fantastic 'for' Statement
What is 'for' statement?

•Iterates code block       ## repeat 100 times
 ブロックを繰り返す機能               for i in xrange(100):
 •ex: repeat block for N     print("i=%s" % i)
  times
   例:ブロックをN回実行             ## read lines from file
                           with open('file') as f:
 •ex: read each line         for line in f:
  from opened file
                                print(line)
  例:オープンしたファイルから
  1行ずつ読み込む
How to use 'for' statement in DSL? #1

•Appends pre-
                             Append pre-process
 process and post-                 前処理を追加
 process around

                              }
 iteration block       x=1
 繰り返し用のブロックに
                       y=2        iteration block
 前処理と後処理をくっつける         z=3

                            Append post-process
                                   後処理を追加
How to use 'for' statement in DSL? #1

•Appends pre-
                       def gfunc():
 process and post-
 process around
 iteration block
                         ....
                         ....   }pre-process

 繰り返し用のブロックに             for i in xrange(n):

                                    } exec block
 前処理と後処理をくっつける

                           yield
                         ....
                         ....   }    post-process
Case Study: Start/Stop time (Benchmarker)

## before              ## after
t1 = time.time()       bm = Benchmarker(
for i in xrange(N):             repeat=N)
   func1()             for _ in bm('func'):
t2 = time.time()         func1()
print('func: %s'
        % (t2-t1))
How to use 'for' statement in DSL? #2

•Iterate code block
                        def gfunc():
 only once
 ブロックを1回だけ繰り返す
                          ....
                          ....  } pre-process

                          yield } exec block
                                   (only once!)
•Emulates 'with' stmt     ....
 by 'for' stmt            .... }  post-process
 with文をfor文でエミュレート
Case Study: Change Directory (Kook)

## before               ## after
chdir('tmp')            for _ in chdir('tmp'):
cp('../file', 'file')     cp('../file', 'file')
system('cmd...')          system('cmd...')
chdir('..')

                          Use 'for' as alternative
                          of 'with' in Python 2.4
                          Python2.4では 'with' が使えない
                          ので、代わりとして 'for' を使う
How to use 'for' statement in DSL? #3

•Iterate block in 0 or
                         def gfunc():
 1 time
 ブロックを0回または1回だけ
 繰り返す
                           ....
                           ....   }pre-process

                           if condition:

                                      }
•Emulates 'if' stmt by
 'for' stmt to skip           yield       exec block
 block according to        ....
 condition
 if文をfor文でエミュレートし、条
                           ....   }   post-process

 件によってブロックをスキップ
Case Study: Fragment Cache (Tenjin)

 <div>
 % for _ in cache("key", 60*60*1):
   <ul>
   % for item in get_items():
   <li>${item}</li>
   % endfor         You can skip block when
   </ul>           cache is not expired! Wow!
 % endfor          with文と違い、キャッシュが生きている

 </div>            ときにブロックをスキップできる! ステキ!
Case Study: Java and JSP

 <div>
 <% for (int _: cache("key",60)) { %>
   <ul>
   <% for (Item item: getItems()) { %>
   <li>${item}</li>
   <% } %>
   </ul>
 <% } %>
 </div>
Fantastic Decorator
What is Decorator?

•Higher-order function   class Hello(object):
 to manipulate
 declaring function or    @classmethod
 class                    def fn(cls):
 宣言中の関数やクラスを操作する            print("Hello")
 高階関数

 •ex: @classmethod(),     ## above is same as
      @property()         def fn(cls):
   例:@classmethod(),
                            print("Hello")
      @property           fn = classmethod(fn)
How to use Decorator in DSL? #1

•Mark function with
                      def deco(func):
 or without args
                       func._mark = True
 関数に目印をつける
                       return func

                      def deco_with(arg):
                       def deco(func):
                         func._mark = arg
                         return func
                       deco
Case Study: Marking and Options (Kook)

@recipe
def test(c):
 system("python -m oktest test")

@recipe("*.o")
@ingreds("$(1).c", if_exist="$(1).h")
def file_o(c):
 system(c%'gcc -o $(product) $(ingred)')
How to use Decorator in DSL? #2

•Syntax sugar to
                      def fn(arg):
 pass function arg
                        print(arg)
 引数として関数を渡すときの
 シンタックスシュガー           func(x, y, fn)



                      @func(x, y)
                      def fn(arg):
                        print(arg)
Case Study: Event Handler

## before              ## after
def _():               @button.onclick
 do()                  def _():
 some()                  do()
 thing()                 some()
button.onclick(_)        thing()
                            More readable because
                            @onclick appears first
                              ブロックより先に@onclickが
                              きているのでより読みやすい
Case Study: Database Transaction

## before              ## after
def _():               @transaction
  do()                 def _():
  some()                 do()
  thing()                some()
transaction(_)           thing()
                         More readable because
                        @transaction appears first
                          ブロックより先に@transactionが
                           現れるので、より読みやすい
Case Study: unittest

## before               ## after
def _():                @assertRaise2(Err)
  do()                  def _():
  some()                 do()
  thing()                some()
assertRaise(Err, _)      thing()

                        More readable because
                       assertRailse() appears first
                       assertRaises2()のほうがブロックより
                        先に現れるので、より読みやすい
How to use Decorator in DSL? #3

•Alternative syntax of
                         with func(arg) as x:
 with- or for-
                           ....
 statement
 with文やfor文の代替

  •Independent scope!
   独立したスコープ!
                         @func(arg)
  •Nested scope!         def _(x):
   入れ子になったスコープ!            ....
Case Study: open()

## before            ## after
with open('file',    @open('file', 'w')
'w') as f:           def _(f):
  f.write("....")      f.write("....")
How to use Decorator in DSL? #4

•Alternative syntax of
                           class Foo(object):
 class definition
                              def meth1(self):
 class定義の代替
                                ....
  •More natural
   representation of
   inheritance structure
                           @classdef
   継承構造のより自然な表現
                           def _():
  •More natural scope        @methoddef
   より自然なスコープ
                             def _():
                                ....
Class Inheritance

class Parent(object):
   ....

class Child(Parent):
   ....
                        Inheritance structure
class Baby(Child):        is not represented
   ....                         visually
                          継承構造が視覚的には
                           表現されていない
Nested Class Definition

class Parent(object):

  class Child(Parent):
                               Represents
     class Baby(Child):   inheritance structure
        ....                 visually, but not
                           possible in Python!
                            こう書けば継承構造が視
                            覚的に表現できるけど、
                            Pythonではこう書けない!
Nested Structure by with-statement

with define('Parent'):

  with define('Child'):

     with define('Baby'):    Represents structure
       ....                   visually, but scopes
                             are not independent
                              構造は視覚的に表現でき
                              ているが、スコープが独
                              立していない (共有される)
Nested Structure with Decorator

@defclass
def Parent():

  @defclass
  def Child():               Represents structure
                             visually, and scopes
     @defclass                  are not shared
     def Baby():              継承構造を視覚的に表現
                              できるし、スコープも共
       ....                   有されない (独立している)
Strange Scope Rule (for beginner) in Class Definition

1: class Outer(object):
2: VAR = 1
3:
4: class Inner(object):
5:      # error
6:      print(VAR)                Why I can't access
7:      # error, too              to outer variable?
8:      print(Outer.VAR)            どうして外側の変数に
                                    アクセスできないの?
Natural Scope Rule (for beginner) with Function

1: def outer():
2: VAR = 1
3:
4: def middle():
5:      print(VAR) # OK                More natual
6:                                     scope rule
7:      def inner():              (especially for beginner)

8:         print(VAR) # OK         より自然なスコープルール
                                    (特に初心者にとっては)
Case Study: RSpec

describe("Class1") do

  describe("#method1()") do

   it("should return None") do
     Class1.new.method1().should be_nil
   end

 end
end
Case Study: RSpec

class Class1Test(TestCase):

  class method1Test(Class1Test):

   def test_should_return_None(self):
    assert Class1().method1() is None
Case Study: RSpec

@describe("Class1")
def _():

  @describe("#method1()")
  def _():

    @it("should return None")
    def _(self):
      assert Class1().method1() is None
Case Study: RSpec

@describe("Class1")
def _():        Variables in outer are...
  def this():    外側の関数で定義された変数に...

     return Class1()
  @describe("#method1()")
  def _():
     @it("should return None")
     def _(self):
       assert this().method1() is None
                    Accessable from inner!
                  内側の関数から自然にアクセスできる!
Fantastic Operator
Operator Override


 1: class Node(object):
 2: def __init__(self, op, left, right):
 3:      self.op, self.left, self.right = 
 4: Overrides '==' operator   op, left, right
 5:
 6: def __eq__(self, other):
 7:      return Node('==', self, other)
 8: def __ne__(self, other):
 9:      return Node('!=', self, other)
               Overrides '!=' operator
Expression Evaluation v.s. AST

Expression Evaluation

           x+1                                          2

AST (Abstract Syntax Tree)
                                                            +
           x+1
                                                        x       1
参考: http://www.slideshare.net/kwatch/dsl-presentation
Case Study: Modern O/R Mapper (SQLAlchemy)
 Python                            SQL


                     ==
 x == 1                           x=1
                 x        1

                     ==
x == None                         x is null
                 x    None
Case Study: Assertion (Oktest)

Assertion                 When Failed
 ##	 Python	 	 	 	 	 	 	 	 	 AssertionError:
 assert	 x	 ==	 y	 	 	 	 	 	 (no message)

 ##	 Nose	 	 	 	 	 	 	 	 	 	 	 AssertionError:
 ok_(x	 ==	 y)	 	 	 	 	 	 	 	 (no message)

 ##	 Oktest	 	 	 	 	 	 	 	 	 AssertionError:
 ok	 (x)	 ==	 y	 	 	 	 	 	 	 	 1	 ==	 2	 :	 failed
                    Shows actual & expected values
                     失敗時に、実際値と期待値を表示してくれる
Case Study: Assertion (Oktest)

Oktest                    Oktest() returns AssertionObject
                           ok() はAssertionObject のインスタンスを返す
 >>> ok (1+1)
 <oktest.AssertionObject object>

 >>> ok (1+1).__eq__(1)
 Traceback (most recent call last):
  ...
 AssertionError: 2 == 1 : failed.
                                  Overrides '==' operator
                                 '==' 演算子をオーバーライドしている


参考: http://goo.gl/C6Eun
Case Study: String Interpolation (Kook)

CMD	 =	 'rst2html	 -i	 utf-8'

@recipe('*.html')
@ingreds('$(1).txt')                   Low readability
def	 file_html(c):                        可読性が低い

	 	 system("%s	 %s	 >	 %s"	 %	 
	 	 	 	 	 	 	 	 	 	 (CMD,	 c.ingreds[0],	 c.product))
	 	 #	 or
	 	 cmd,prod,ingred	 =	 CC,c.product,c.ingreds[0]
	 	 system("%(cmd)s	 %(ingred)s	 >	 %(prod)s"	 %
	 	 	 	 	 	 	 	 	 	 	 locals())
                                  Name only, No expression
                                 名前のみで式が使えない
Case Study: String Interpolation (Kook)
    http://www.kuwata-lab.com/kook/pykook-users-guide.html#cookbook-prod

 CMD	 =	 'rst2html	 -i	 utf-8'

 @recipe('hello')
 @ingreds('hello.c')
 def	 compile(c):
 	 	 prod,	 ingreds	 =	 c.product,	 c.ingreds
 	 	 system(c%"$(CMD)	 $(ingreds[0])	 >	 $(prod)")

 Operator                                              Indexing
 override              Both global and                 available
演算子オーバーライド            local var available               添字も利用可能

                       グローバル変数とローカル
                        変数の両方が利用可能
Case Study: Method Chain Finishing Problem


 AppointmentBuilder()	 
 	 .From(1300)	 
 	 .To(1400)	 
 	 .For("Dental")	 
 	 .done()
         Method chain requires end of chain.
       メソッドチェーンでは、チェーンの終わりを明示する必要がある
Case Study: Method Chain Finishing Problem


 -	 AppointmentBuilder()	 
 	 	 	 .From(1300)	 
 	 	 	 .To(1400)	 
 	 	 	 .For("Dental")

     Unary operator works at end of chain!
         単項演算子はチェーンの終わりに実行される!

     Very similar to unordered list or bullet!
                見た目が箇条書きそっくり!
Reflected operator


 class	 Foo(object):

 	 	 def	 __add__(self,	 other):
 	 	 	 	 ...   foo + 1


 	 	 def	 __radd__(self,	 other):
 	 	 	 	 ...    1 + foo
Reflected operator


 def	 __add__(self,	 other):
 	 	 	 ...
 int.__add__	 =	 __add__
 1	 +	 Foo()    Not possible ;<
                    Pythonではできない

 class	 Foo(object):
 	 	 	 def	 __radd__(self,	 other):
 	 	 	 	 	 	 ...  No problem :)
 1	 +	 Foo()         問題なし
Case Study: Should DSL
                                http://www.should-dsl.info/

def	 test1(self):
	 	 self.player	 |should|	 have(11).cards

def	 test2(self):
	 	 self.player.name	 |should|	 
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 equal_to('John	 Doe')

         Instead of adding method to any object,
          use bit operator which has low priority
        ビットOR演算子の優先順位が低いことを利用して、任意のオブジェクトに
         メソッドを追加できないというPythonの欠点を克服した、絶妙なDSL
One more thing...
DSL設計者に贈る言葉

「キモイ」は褒め言葉!

古参のイチャモンは新規性の証し!

オレが書きたいように書けないのはPythonが悪い!
おしまい

More Related Content

PPTX
純粋関数型アルゴリズム入門
PDF
中3女子でもわかる constexpr
PDF
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
PDF
ゲーム開発者のための C++11/C++14
PPTX
F#のコンピュテーション式
PDF
Pythonによる黒魔術入門
PDF
磯野ー!関数型言語やろうぜー!
PDF
関数型プログラミングのデザインパターンひとめぐり
純粋関数型アルゴリズム入門
中3女子でもわかる constexpr
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
ゲーム開発者のための C++11/C++14
F#のコンピュテーション式
Pythonによる黒魔術入門
磯野ー!関数型言語やろうぜー!
関数型プログラミングのデザインパターンひとめぐり

What's hot (20)

PDF
圏論のモナドとHaskellのモナド
KEY
ラムダ計算入門
PDF
プログラムの処方箋~健康なコードと病んだコード
PDF
オブジェクト指向エクササイズのススメ
PPTX
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
PDF
Where狙いのキー、order by狙いのキー
PDF
がんばらなくても C# で Single Page Web アプリケーションが書けてしまう「Blazor」とは
PPT
メタプログラミングって何だろう
PDF
ソーシャルゲームスケールアウトの歴史
PDF
PostgreSQLアーキテクチャ入門
PDF
イミュータブルデータモデルの極意
PDF
実践イカパケット解析
PDF
オブジェクト指向できていますか?
KEY
やはりお前らのMVCは間違っている
PDF
ダブル配列の実装方法
PPTX
C#とILとネイティブと
PDF
並行処理初心者のためのAkka入門
PDF
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
PDF
すごい constexpr たのしくレイトレ!
PDF
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
圏論のモナドとHaskellのモナド
ラムダ計算入門
プログラムの処方箋~健康なコードと病んだコード
オブジェクト指向エクササイズのススメ
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
Where狙いのキー、order by狙いのキー
がんばらなくても C# で Single Page Web アプリケーションが書けてしまう「Blazor」とは
メタプログラミングって何だろう
ソーシャルゲームスケールアウトの歴史
PostgreSQLアーキテクチャ入門
イミュータブルデータモデルの極意
実践イカパケット解析
オブジェクト指向できていますか?
やはりお前らのMVCは間違っている
ダブル配列の実装方法
C#とILとネイティブと
並行処理初心者のためのAkka入門
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
すごい constexpr たのしくレイトレ!
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
Ad

Viewers also liked (18)

PDF
Creating Domain Specific Languages in Python
PDF
20 examples on Domain-Specific Modeling Languages
PPTX
Domain-Specific Languages
PPT
Internal DSLs For Automated Functional Testing
PPTX
DSL in test automation
PPTX
Real world DSL - making technical and business people speaking the same language
PDF
Using Scala for building DSLs
PDF
DSLs in JavaScript
KEY
The Unbearable Stupidity of Modeling
PPTX
おしゃべりゆかり 外部ツールによるMMDAgent操作
PDF
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
PDF
Scala DSLの作り方
PDF
A Field Guide to DSL Design in Scala
PPTX
Logic programming in python
ODP
Introducción a DSL (Lenguajes Específicos de Dominios) con Python
PDF
RubyでDSL
PPTX
How Spark is Making an Impact at Goldman Sachs by Vincent Saulys
PDF
SI屋のためのF# ~DSL編~
Creating Domain Specific Languages in Python
20 examples on Domain-Specific Modeling Languages
Domain-Specific Languages
Internal DSLs For Automated Functional Testing
DSL in test automation
Real world DSL - making technical and business people speaking the same language
Using Scala for building DSLs
DSLs in JavaScript
The Unbearable Stupidity of Modeling
おしゃべりゆかり 外部ツールによるMMDAgent操作
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
Scala DSLの作り方
A Field Guide to DSL Design in Scala
Logic programming in python
Introducción a DSL (Lenguajes Específicos de Dominios) con Python
RubyでDSL
How Spark is Making an Impact at Goldman Sachs by Vincent Saulys
SI屋のためのF# ~DSL編~
Ad

Similar to Fantastic DSL in Python (20)

PPTX
Let's LL
PDF
Coding in Style
PDF
Friendly Functional Programming
PDF
Learn You Some Erlang for great good! 日本語化プロジェクト
ODP
Using Functional Programming to improve your code: A working example
PDF
Pydiomatic
PDF
Python idiomatico
PDF
エンタープライズ・クラウドと 並列・分散・非同期処理
PDF
Continuation Passing Style and Macros in Clojure - Jan 2012
PDF
The Evolution of Scala / Scala進化論
PDF
Simple is better than complex. ~私がPythonを愛する理由~
PDF
人力
PDF
第二回CTF勉強会資料
PDF
sbt core concepts (ScalaMatsuri 2019)
PDF
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術
PPTX
Eureka English Evening
PDF
C++0x Variadic Type List
PDF
Object Orientation vs Functional Programming in Python
PDF
How To Use Scala At Work - Airframe In Action at Arm Treasure Data
PDF
Building Interpreters with PyPy
Let's LL
Coding in Style
Friendly Functional Programming
Learn You Some Erlang for great good! 日本語化プロジェクト
Using Functional Programming to improve your code: A working example
Pydiomatic
Python idiomatico
エンタープライズ・クラウドと 並列・分散・非同期処理
Continuation Passing Style and Macros in Clojure - Jan 2012
The Evolution of Scala / Scala進化論
Simple is better than complex. ~私がPythonを愛する理由~
人力
第二回CTF勉強会資料
sbt core concepts (ScalaMatsuri 2019)
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術
Eureka English Evening
C++0x Variadic Type List
Object Orientation vs Functional Programming in Python
How To Use Scala At Work - Airframe In Action at Arm Treasure Data
Building Interpreters with PyPy

More from kwatch (20)

PDF
How to make the fastest Router in Python
PDF
Migr8.rb チュートリアル
PDF
なんでもID
PDF
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
PDF
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
PDF
O/Rマッパーによるトラブルを未然に防ぐ
PDF
正規表現リテラルは本当に必要なのか?
PDF
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
PDF
DBスキーマもバージョン管理したい!
PDF
PHPとJavaScriptにおけるオブジェクト指向を比較する
PDF
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
PDF
PHP5.5新機能「ジェネレータ」初心者入門
PDF
Pretty Good Branch Strategy for Git/Mercurial
PDF
Oktest - a new style testing library for Python -
PDF
文字列結合のベンチマークをいろんな処理系でやってみた
PDF
I have something to say about the buzz word "From Java to Ruby"
PDF
Cより速いRubyプログラム
PDF
Javaより速いLL用テンプレートエンジン
PDF
Underlaying Technology of Modern O/R Mapper
PDF
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to make the fastest Router in Python
Migr8.rb チュートリアル
なんでもID
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
O/Rマッパーによるトラブルを未然に防ぐ
正規表現リテラルは本当に必要なのか?
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
DBスキーマもバージョン管理したい!
PHPとJavaScriptにおけるオブジェクト指向を比較する
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
PHP5.5新機能「ジェネレータ」初心者入門
Pretty Good Branch Strategy for Git/Mercurial
Oktest - a new style testing library for Python -
文字列結合のベンチマークをいろんな処理系でやってみた
I have something to say about the buzz word "From Java to Ruby"
Cより速いRubyプログラム
Javaより速いLL用テンプレートエンジン
Underlaying Technology of Modern O/R Mapper
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -

Recently uploaded (20)

PDF
Network Security Unit 5.pdf for BCA BBA.
PPT
Teaching material agriculture food technology
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Electronic commerce courselecture one. Pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
KodekX | Application Modernization Development
PDF
Approach and Philosophy of On baking technology
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
sap open course for s4hana steps from ECC to s4
PDF
cuic standard and advanced reporting.pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPTX
Spectroscopy.pptx food analysis technology
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Empathic Computing: Creating Shared Understanding
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Encapsulation theory and applications.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
Network Security Unit 5.pdf for BCA BBA.
Teaching material agriculture food technology
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Electronic commerce courselecture one. Pdf
Programs and apps: productivity, graphics, security and other tools
KodekX | Application Modernization Development
Approach and Philosophy of On baking technology
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
MIND Revenue Release Quarter 2 2025 Press Release
sap open course for s4hana steps from ECC to s4
cuic standard and advanced reporting.pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Spectroscopy.pptx food analysis technology
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Empathic Computing: Creating Shared Understanding
“AI and Expert System Decision Support & Business Intelligence Systems”
Encapsulation theory and applications.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
NewMind AI Weekly Chronicles - August'25 Week I
Reach Out and Touch Someone: Haptics and Empathic Computing

Fantastic DSL in Python

  • 1. PyConJP 2012 Fantastic DSL in Python Makoto Kuwata <kwa@kuwata-lab.com> http://www.kuwata-lab.com/ 2012-09-16 (Sun) Video: http://www.youtube.com/watch?v=l8ptNmtB0G8
  • 2. Agenda •About DSL •Fantastic 'with' statement •Fantastic 'for' statement •Fantastic Decorator •Fantastic Operator
  • 4. What is DSL (Domain Specific Language?) DSL Google Search
  • 5. Internal DSL v.s. External DSL •Internal DSL (内部DSL) •Written inside an existing host language 既存の言語を使って、その言語の文法を使って書かれたDSL •No need to implement parser パーサを書く必要なし •Some lang are not good at internal DSL 言語によっては苦手な場合がある •External DSL (外部DSL) Python? •Original, indendent syntax 独自の文法 •Need to implement parser パーサを実装する必要あり •All languages have same power about external DSL 言語による得手不得手は、ほぼない
  • 7. What is 'with' statement? •Enforces finishing ## Python 2.4 process f = open('file') 終了処理を強制する機能 try: •ex: close opened file text = f.read() certainly finally: 例:ファイルを必ず閉じる f.close() ## Python 2.5 or later with open('file') as f: text = f.read()
  • 8. How to use 'with' statement in DSL? •Appends pre- Append pre-process process and post- 前処理を追加 process around } block x=1 ブロックに前処理と後処理をくっ y=2 code block つける z=3 Append post-process 後処理を追加
  • 9. Case Study: Change Directory (Kook) ## before ## after chdir('build') with chdir('build'): cp('../file', 'file') cp('../file', 'file') system('cmd...') system('cmd...') chdir('..')
  • 10. Case Study: Start/Stop time (Benchmarker) ## before ## after t1 = time.time() bm = Benchmarker() for i in xrange(N): with bm('func'): func() for i in xrange(N): t2 = time.time() func() print('func: %s' % (t2-t1))
  • 11. Case Study: Form Builder ## before <form action="/" method="POST"> <input type="hidden" name="_csrf" value="${request.csrf()}" /> <input type="text" ... /> <input type="submit" ... /> </form>
  • 12. Case Study: Form Builder ## after % with FormBuilder(request, "/") as fb: <input type="text" ... /> <input type="submit" ... /> % endwith
  • 13. Pitfall: Variable Scope with test("arithmetic operation"): with test("1+1 should be 1"): x = 1+1 assert x == 2 with test("1-1 should be 0"): x = 1-1 Identical variable because assert x == 0 scope is not independented スコープが独立してないので変数も共有される
  • 14. Pitfall: Cannot Skip Block! <div> % with cache("key", 60*60*1): <ul> % for item in get_items(): <li>${item}</li> % endfor You may want to skip block </ul> when cache is not expired, % endwith but Python doesn't allow it! </div> キャッシュが生きている間はブロックを スキップしたいんだけど、実はできない
  • 16. What is 'for' statement? •Iterates code block ## repeat 100 times ブロックを繰り返す機能 for i in xrange(100): •ex: repeat block for N print("i=%s" % i) times 例:ブロックをN回実行 ## read lines from file with open('file') as f: •ex: read each line for line in f: from opened file print(line) 例:オープンしたファイルから 1行ずつ読み込む
  • 17. How to use 'for' statement in DSL? #1 •Appends pre- Append pre-process process and post- 前処理を追加 process around } iteration block x=1 繰り返し用のブロックに y=2 iteration block 前処理と後処理をくっつける z=3 Append post-process 後処理を追加
  • 18. How to use 'for' statement in DSL? #1 •Appends pre- def gfunc(): process and post- process around iteration block .... .... }pre-process 繰り返し用のブロックに for i in xrange(n): } exec block 前処理と後処理をくっつける yield .... .... } post-process
  • 19. Case Study: Start/Stop time (Benchmarker) ## before ## after t1 = time.time() bm = Benchmarker( for i in xrange(N): repeat=N) func1() for _ in bm('func'): t2 = time.time() func1() print('func: %s' % (t2-t1))
  • 20. How to use 'for' statement in DSL? #2 •Iterate code block def gfunc(): only once ブロックを1回だけ繰り返す .... .... } pre-process yield } exec block (only once!) •Emulates 'with' stmt .... by 'for' stmt .... } post-process with文をfor文でエミュレート
  • 21. Case Study: Change Directory (Kook) ## before ## after chdir('tmp') for _ in chdir('tmp'): cp('../file', 'file') cp('../file', 'file') system('cmd...') system('cmd...') chdir('..') Use 'for' as alternative of 'with' in Python 2.4 Python2.4では 'with' が使えない ので、代わりとして 'for' を使う
  • 22. How to use 'for' statement in DSL? #3 •Iterate block in 0 or def gfunc(): 1 time ブロックを0回または1回だけ 繰り返す .... .... }pre-process if condition: } •Emulates 'if' stmt by 'for' stmt to skip yield exec block block according to .... condition if文をfor文でエミュレートし、条 .... } post-process 件によってブロックをスキップ
  • 23. Case Study: Fragment Cache (Tenjin) <div> % for _ in cache("key", 60*60*1): <ul> % for item in get_items(): <li>${item}</li> % endfor You can skip block when </ul> cache is not expired! Wow! % endfor with文と違い、キャッシュが生きている </div> ときにブロックをスキップできる! ステキ!
  • 24. Case Study: Java and JSP <div> <% for (int _: cache("key",60)) { %> <ul> <% for (Item item: getItems()) { %> <li>${item}</li> <% } %> </ul> <% } %> </div>
  • 26. What is Decorator? •Higher-order function class Hello(object): to manipulate declaring function or @classmethod class def fn(cls): 宣言中の関数やクラスを操作する print("Hello") 高階関数 •ex: @classmethod(), ## above is same as @property() def fn(cls): 例:@classmethod(), print("Hello") @property fn = classmethod(fn)
  • 27. How to use Decorator in DSL? #1 •Mark function with def deco(func): or without args func._mark = True 関数に目印をつける return func def deco_with(arg): def deco(func): func._mark = arg return func deco
  • 28. Case Study: Marking and Options (Kook) @recipe def test(c): system("python -m oktest test") @recipe("*.o") @ingreds("$(1).c", if_exist="$(1).h") def file_o(c): system(c%'gcc -o $(product) $(ingred)')
  • 29. How to use Decorator in DSL? #2 •Syntax sugar to def fn(arg): pass function arg print(arg) 引数として関数を渡すときの シンタックスシュガー func(x, y, fn) @func(x, y) def fn(arg): print(arg)
  • 30. Case Study: Event Handler ## before ## after def _(): @button.onclick do() def _(): some() do() thing() some() button.onclick(_) thing() More readable because @onclick appears first ブロックより先に@onclickが きているのでより読みやすい
  • 31. Case Study: Database Transaction ## before ## after def _(): @transaction do() def _(): some() do() thing() some() transaction(_) thing() More readable because @transaction appears first ブロックより先に@transactionが 現れるので、より読みやすい
  • 32. Case Study: unittest ## before ## after def _(): @assertRaise2(Err) do() def _(): some() do() thing() some() assertRaise(Err, _) thing() More readable because assertRailse() appears first assertRaises2()のほうがブロックより 先に現れるので、より読みやすい
  • 33. How to use Decorator in DSL? #3 •Alternative syntax of with func(arg) as x: with- or for- .... statement with文やfor文の代替 •Independent scope! 独立したスコープ! @func(arg) •Nested scope! def _(x): 入れ子になったスコープ! ....
  • 34. Case Study: open() ## before ## after with open('file', @open('file', 'w') 'w') as f: def _(f): f.write("....") f.write("....")
  • 35. How to use Decorator in DSL? #4 •Alternative syntax of class Foo(object): class definition def meth1(self): class定義の代替 .... •More natural representation of inheritance structure @classdef 継承構造のより自然な表現 def _(): •More natural scope @methoddef より自然なスコープ def _(): ....
  • 36. Class Inheritance class Parent(object): .... class Child(Parent): .... Inheritance structure class Baby(Child): is not represented .... visually 継承構造が視覚的には 表現されていない
  • 37. Nested Class Definition class Parent(object): class Child(Parent): Represents class Baby(Child): inheritance structure .... visually, but not possible in Python! こう書けば継承構造が視 覚的に表現できるけど、 Pythonではこう書けない!
  • 38. Nested Structure by with-statement with define('Parent'): with define('Child'): with define('Baby'): Represents structure .... visually, but scopes are not independent 構造は視覚的に表現でき ているが、スコープが独 立していない (共有される)
  • 39. Nested Structure with Decorator @defclass def Parent(): @defclass def Child(): Represents structure visually, and scopes @defclass are not shared def Baby(): 継承構造を視覚的に表現 できるし、スコープも共 .... 有されない (独立している)
  • 40. Strange Scope Rule (for beginner) in Class Definition 1: class Outer(object): 2: VAR = 1 3: 4: class Inner(object): 5: # error 6: print(VAR) Why I can't access 7: # error, too to outer variable? 8: print(Outer.VAR) どうして外側の変数に アクセスできないの?
  • 41. Natural Scope Rule (for beginner) with Function 1: def outer(): 2: VAR = 1 3: 4: def middle(): 5: print(VAR) # OK More natual 6: scope rule 7: def inner(): (especially for beginner) 8: print(VAR) # OK より自然なスコープルール (特に初心者にとっては)
  • 42. Case Study: RSpec describe("Class1") do describe("#method1()") do it("should return None") do Class1.new.method1().should be_nil end end end
  • 43. Case Study: RSpec class Class1Test(TestCase): class method1Test(Class1Test): def test_should_return_None(self): assert Class1().method1() is None
  • 44. Case Study: RSpec @describe("Class1") def _(): @describe("#method1()") def _(): @it("should return None") def _(self): assert Class1().method1() is None
  • 45. Case Study: RSpec @describe("Class1") def _(): Variables in outer are... def this(): 外側の関数で定義された変数に... return Class1() @describe("#method1()") def _(): @it("should return None") def _(self): assert this().method1() is None Accessable from inner! 内側の関数から自然にアクセスできる!
  • 47. Operator Override 1: class Node(object): 2: def __init__(self, op, left, right): 3: self.op, self.left, self.right = 4: Overrides '==' operator op, left, right 5: 6: def __eq__(self, other): 7: return Node('==', self, other) 8: def __ne__(self, other): 9: return Node('!=', self, other) Overrides '!=' operator
  • 48. Expression Evaluation v.s. AST Expression Evaluation x+1 2 AST (Abstract Syntax Tree) + x+1 x 1 参考: http://www.slideshare.net/kwatch/dsl-presentation
  • 49. Case Study: Modern O/R Mapper (SQLAlchemy) Python SQL == x == 1 x=1 x 1 == x == None x is null x None
  • 50. Case Study: Assertion (Oktest) Assertion When Failed ## Python AssertionError: assert x == y (no message) ## Nose AssertionError: ok_(x == y) (no message) ## Oktest AssertionError: ok (x) == y 1 == 2 : failed Shows actual & expected values 失敗時に、実際値と期待値を表示してくれる
  • 51. Case Study: Assertion (Oktest) Oktest Oktest() returns AssertionObject ok() はAssertionObject のインスタンスを返す >>> ok (1+1) <oktest.AssertionObject object> >>> ok (1+1).__eq__(1) Traceback (most recent call last): ... AssertionError: 2 == 1 : failed. Overrides '==' operator '==' 演算子をオーバーライドしている 参考: http://goo.gl/C6Eun
  • 52. Case Study: String Interpolation (Kook) CMD = 'rst2html -i utf-8' @recipe('*.html') @ingreds('$(1).txt') Low readability def file_html(c): 可読性が低い system("%s %s > %s" % (CMD, c.ingreds[0], c.product)) # or cmd,prod,ingred = CC,c.product,c.ingreds[0] system("%(cmd)s %(ingred)s > %(prod)s" % locals()) Name only, No expression 名前のみで式が使えない
  • 53. Case Study: String Interpolation (Kook) http://www.kuwata-lab.com/kook/pykook-users-guide.html#cookbook-prod CMD = 'rst2html -i utf-8' @recipe('hello') @ingreds('hello.c') def compile(c): prod, ingreds = c.product, c.ingreds system(c%"$(CMD) $(ingreds[0]) > $(prod)") Operator Indexing override Both global and available 演算子オーバーライド local var available 添字も利用可能 グローバル変数とローカル 変数の両方が利用可能
  • 54. Case Study: Method Chain Finishing Problem AppointmentBuilder() .From(1300) .To(1400) .For("Dental") .done() Method chain requires end of chain. メソッドチェーンでは、チェーンの終わりを明示する必要がある
  • 55. Case Study: Method Chain Finishing Problem - AppointmentBuilder() .From(1300) .To(1400) .For("Dental") Unary operator works at end of chain! 単項演算子はチェーンの終わりに実行される! Very similar to unordered list or bullet! 見た目が箇条書きそっくり!
  • 56. Reflected operator class Foo(object): def __add__(self, other): ... foo + 1 def __radd__(self, other): ... 1 + foo
  • 57. Reflected operator def __add__(self, other): ... int.__add__ = __add__ 1 + Foo() Not possible ;< Pythonではできない class Foo(object): def __radd__(self, other): ... No problem :) 1 + Foo() 問題なし
  • 58. Case Study: Should DSL http://www.should-dsl.info/ def test1(self): self.player |should| have(11).cards def test2(self): self.player.name |should| equal_to('John Doe') Instead of adding method to any object, use bit operator which has low priority ビットOR演算子の優先順位が低いことを利用して、任意のオブジェクトに メソッドを追加できないというPythonの欠点を克服した、絶妙なDSL