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

What's hot (20)

PDF
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
Yoshio Hanawa
 
PDF
新しい並列for構文のご提案
yohhoy
 
PDF
規格書で読むC++11のスレッド
Kohsuke Yuasa
 
PDF
プログラムを高速化する話
京大 マイコンクラブ
 
PPTX
イベント駆動プログラミングとI/O多重化
Gosuke Miyashita
 
PDF
SystemC Tutorial
kocha2012
 
PDF
今日からできる!簡単 .NET 高速化 Tips
Takaaki Suzuki
 
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
onozaty
 
PPT
メタプログラミングって何だろう
Kota Mizushima
 
PDF
Where狙いのキー、order by狙いのキー
yoku0825
 
PPTX
MongoDBが遅いときの切り分け方法
Tetsutaro Watanabe
 
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
Koichiro Matsuoka
 
PDF
ヤフー社内でやってるMySQLチューニングセミナー大公開
Yahoo!デベロッパーネットワーク
 
PDF
アンチフラジャイルの世界
Yoshitaka Kawashima
 
PDF
Constexpr 中3女子テクニック
Genya Murakami
 
PDF
モダン PHP テクニック 12 選 ―PsalmとPHP 8.1で今はこんなこともできる!―
shinjiigarashi
 
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
Koichiro Matsuoka
 
PPT
Glibc malloc internal
Motohiro KOSAKI
 
PDF
メルカリ・ソウゾウでは どうGoを活用しているのか?
Takuya Ueda
 
PDF
Docker道場オンライン#1 Docker基礎概念と用語の理解
Masahito Zembutsu
 
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
Yoshio Hanawa
 
新しい並列for構文のご提案
yohhoy
 
規格書で読むC++11のスレッド
Kohsuke Yuasa
 
プログラムを高速化する話
京大 マイコンクラブ
 
イベント駆動プログラミングとI/O多重化
Gosuke Miyashita
 
SystemC Tutorial
kocha2012
 
今日からできる!簡単 .NET 高速化 Tips
Takaaki Suzuki
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
onozaty
 
メタプログラミングって何だろう
Kota Mizushima
 
Where狙いのキー、order by狙いのキー
yoku0825
 
MongoDBが遅いときの切り分け方法
Tetsutaro Watanabe
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
Koichiro Matsuoka
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
Yahoo!デベロッパーネットワーク
 
アンチフラジャイルの世界
Yoshitaka Kawashima
 
Constexpr 中3女子テクニック
Genya Murakami
 
モダン PHP テクニック 12 選 ―PsalmとPHP 8.1で今はこんなこともできる!―
shinjiigarashi
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
Koichiro Matsuoka
 
Glibc malloc internal
Motohiro KOSAKI
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
Takuya Ueda
 
Docker道場オンライン#1 Docker基礎概念と用語の理解
Masahito Zembutsu
 

Viewers also liked (18)

PDF
Creating Domain Specific Languages in Python
Siddhi
 
PDF
20 examples on Domain-Specific Modeling Languages
Juha-Pekka Tolvanen
 
PPTX
Domain-Specific Languages
Javier Canovas
 
PPT
Internal DSLs For Automated Functional Testing
John Sonmez
 
PPTX
DSL in test automation
test test
 
PPTX
Real world DSL - making technical and business people speaking the same language
Mario Fusco
 
PDF
Using Scala for building DSLs
IndicThreads
 
PDF
DSLs in JavaScript
elliando dias
 
KEY
The Unbearable Stupidity of Modeling
Peter Friese
 
PPTX
おしゃべりゆかり 外部ツールによるMMDAgent操作
kouji azuma
 
PDF
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
kwatch
 
PDF
Scala DSLの作り方
Tomoharu ASAMI
 
PDF
A Field Guide to DSL Design in Scala
Tomer Gabel
 
PPTX
Logic programming in python
Pierre Carbonnelle
 
ODP
Introducción a DSL (Lenguajes Específicos de Dominios) con Python
Juan Rodríguez
 
PDF
RubyでDSL
Yukimitsu Izawa
 
PPTX
How Spark is Making an Impact at Goldman Sachs by Vincent Saulys
Spark Summit
 
PDF
SI屋のためのF# ~DSL編~
bleis tift
 
Creating Domain Specific Languages in Python
Siddhi
 
20 examples on Domain-Specific Modeling Languages
Juha-Pekka Tolvanen
 
Domain-Specific Languages
Javier Canovas
 
Internal DSLs For Automated Functional Testing
John Sonmez
 
DSL in test automation
test test
 
Real world DSL - making technical and business people speaking the same language
Mario Fusco
 
Using Scala for building DSLs
IndicThreads
 
DSLs in JavaScript
elliando dias
 
The Unbearable Stupidity of Modeling
Peter Friese
 
おしゃべりゆかり 外部ツールによるMMDAgent操作
kouji azuma
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
kwatch
 
Scala DSLの作り方
Tomoharu ASAMI
 
A Field Guide to DSL Design in Scala
Tomer Gabel
 
Logic programming in python
Pierre Carbonnelle
 
Introducción a DSL (Lenguajes Específicos de Dominios) con Python
Juan Rodríguez
 
RubyでDSL
Yukimitsu Izawa
 
How Spark is Making an Impact at Goldman Sachs by Vincent Saulys
Spark Summit
 
SI屋のためのF# ~DSL編~
bleis tift
 
Ad

Similar to Fantastic DSL in Python (20)

PPTX
Let's LL
t_ichioka_sg
 
PDF
Coding in Style
scalaconfjp
 
PDF
Friendly Functional Programming
Wiem Zine Elabidine
 
PDF
Learn You Some Erlang for great good! 日本語化プロジェクト
Yoshifumi Yamaguchi
 
ODP
Using Functional Programming to improve your code: A working example
Jorge Sánchez
 
PDF
Python idiomatico
PyCon Italia
 
PDF
Pydiomatic
rik0
 
PDF
エンタープライズ・クラウドと 並列・分散・非同期処理
maruyama097
 
PDF
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
PDF
The Evolution of Scala / Scala進化論
scalaconfjp
 
PDF
Simple is better than complex. ~私がPythonを愛する理由~
cocodrips
 
PDF
人力
emasaka
 
PDF
第二回CTF勉強会資料
Asuka Nakajima
 
PDF
sbt core concepts (ScalaMatsuri 2019)
Eugene Yokota
 
PDF
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術
Seitaro Yuuki
 
PPTX
Eureka English Evening
James Neve
 
PDF
C++0x Variadic Type List
Akira Takahashi
 
PDF
Object Orientation vs Functional Programming in Python
Tendayi Mawushe
 
PDF
How To Use Scala At Work - Airframe In Action at Arm Treasure Data
Taro L. Saito
 
PDF
Building Interpreters with PyPy
Daniel Neuhäuser
 
Let's LL
t_ichioka_sg
 
Coding in Style
scalaconfjp
 
Friendly Functional Programming
Wiem Zine Elabidine
 
Learn You Some Erlang for great good! 日本語化プロジェクト
Yoshifumi Yamaguchi
 
Using Functional Programming to improve your code: A working example
Jorge Sánchez
 
Python idiomatico
PyCon Italia
 
Pydiomatic
rik0
 
エンタープライズ・クラウドと 並列・分散・非同期処理
maruyama097
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
The Evolution of Scala / Scala進化論
scalaconfjp
 
Simple is better than complex. ~私がPythonを愛する理由~
cocodrips
 
人力
emasaka
 
第二回CTF勉強会資料
Asuka Nakajima
 
sbt core concepts (ScalaMatsuri 2019)
Eugene Yokota
 
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術
Seitaro Yuuki
 
Eureka English Evening
James Neve
 
C++0x Variadic Type List
Akira Takahashi
 
Object Orientation vs Functional Programming in Python
Tendayi Mawushe
 
How To Use Scala At Work - Airframe In Action at Arm Treasure Data
Taro L. Saito
 
Building Interpreters with PyPy
Daniel Neuhäuser
 
Ad

More from kwatch (20)

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

Recently uploaded (20)

PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PDF
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PPTX
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
Wojciech Ciemski for Top Cyber News MAGAZINE. June 2025
Dr. Ludmila Morozova-Buss
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PDF
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
PDF
Smart Air Quality Monitoring with Serrax AQM190 LITE
SERRAX TECHNOLOGIES LLP
 
PPT
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
PDF
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
PDF
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PPTX
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
Wojciech Ciemski for Top Cyber News MAGAZINE. June 2025
Dr. Ludmila Morozova-Buss
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
Smart Air Quality Monitoring with Serrax AQM190 LITE
SERRAX TECHNOLOGIES LLP
 
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 

Fantastic DSL in Python

  • 1. PyConJP 2012 Fantastic DSL in Python Makoto Kuwata <[email protected]> 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