2012年11月19日 星期一

桌面環境awesome


1. 簡介

Awesome Window Manager 的目標,是做個可擴充、可高度自訂的視窗管理員。
為了達到這個目的,awesome 是設計成一個 framework window manager,極為快速、小巧、動態、且可用 Lua programming language 來擴充。

1.1. awesome 的視窗管理

awesome 的視窗管理與傳統的 x-Window-manager 不同,它是用「標籤」來作管理的。
啟動 awesome 後,畫面左上方標示著 one,two…nine,稱為標籤 (tag),one, two, three …… 等就是標籤的名稱。
「標籤」的功能乍用之下有點類似虛擬桌面 (workspace),但其實概念上是很不一樣的東西。
awesome 會給視窗加上「標籤」,當我們選擇 one 時,就代表要顯示具有 one 這個標籤的視窗。如果覺得用小小的標籤管理視窗有點不習慣,不妨將畫面左上的 tag 想成是那個 tag 的 workspace,每當我們選取了某個 tag,就代表我們要顯示那個 tag 所代表的 workspace,每當我們給某個視窗加上 tag,就代表我們將那視窗加入那個 tag 的 workspace。
在 awesome 中,我們可以透過簡單的操作,將視窗加上一或多個標籤,並決定目前螢幕上要顯示具有某個或某幾個標籤的視窗,這讓視窗的管理更具彈性。
例如,我們可以將具有 one, two, three 標籤的視窗都同時顯示在螢幕上,也可以輕易切換為只顯示 one 或 two 標籤的視窗。
也可以給某個視窗加上 one, two, three 三個標籤,如此,無論你現在顯示 one,或 two,或 three,都可以顯示這個視窗。
這些功能,其實並不稀奇,但 awesome 之所以 awesome,是因為這些視窗管理都可以透過簡單的鍵盤、滑鼠來即時操作!

1.2. awesome 版面配置的方式 (layout)

平鋪 (Tiled)使用這種版面配置時,awesome 會把視窗分成主視窗區 (master area) 與堆疊區 (stacking area),主視窗區放置我們目前比較關注的視窗,其他視窗放在堆疊區。主視窗區可切割成好幾列 (row) 與好幾欄 (column),隨你高興。
最大視野 (Max)每個視窗都調整到全螢幕。
放大 (Magnifier)焦點所在的視窗維持在畫面中央並佔用最大的空間,其餘視窗都堆疊到這個視窗後。
浮動 (Floating)可自由改變每個視窗的大小,就像一般的視窗管理員一樣。
不管使用那一種版面配置模式,對話方塊視窗總是以 floating 來處理。

1.3. awesome 的介面元素

狀態列 (Statusbar)可放在螢幕的上下左右邊緣,包含一或多個 widgets。
標題列 (Titlebar)類似狀態列,但是是在視窗的邊緣。
小工具 (Widget)在狀態列或標題列中的東西,可以文字、圖形、進度列、圖表等各種小東西顯示各種資訊。

2. 第一次用 awesome 要知道的

  • 在桌面按滑鼠右鍵,或者 Win + Enter ,可叫出 x-terminal-emulator
  • man awesome
  • man awesomerc
  • Win + 數字 可在不同標籤間切換。
  • Win + j 或 Win + k 可在視窗間切換。
  • Win + Shift + c 可關閉目前視窗。
  • Win + Shift + r 可重新啟動 awesome。

3. 不是第一次使用 awesome 要知道的

  • 用 awesome -k 來檢查設定檔的語法。

4. 預設的滑鼠按鍵功能

  • 在標籤上按 滑鼠左鍵 (Button1 on tag name)
    顯示標有此 tag 的視窗 (View tag)。
    也可想成是 - 切換到那個 tag 所代表的 workspace。
    相當於快捷鍵 Win + 標籤數字 。
  • 在某個標籤上按 Win + 滑鼠左鍵 (Mod4 + Button1 on tag name)
    替目前焦點所在的視窗加上某個標籤 (Tag current client with this tag)。
    舉例來說,假設原本目前視窗有 three 這個標籤,在 five 上按 Win + 滑鼠左鍵 後,會替視窗貼上 five 這個標籤,此時原本的標籤 three 會不見,又因目前顯示的的 tag 還是 three,所以原本視窗會不見,如要顯示原來的視窗,要改顯示 five 這個標籤。
    所以,在某個標籤上按 Win + 滑鼠左鍵 ,等於是 - 把不想看的視窗,放到其他 tag 所代表的 workspace 去的意思。
    如果完全用鍵盤快捷鍵,可用 Win + Shift + 標籤數字 。
  • 在某個標籤上 滑鼠右鍵 (Button3 on tag name)
    在目前的螢幕顯示/隱藏具有某個標籤的視窗 (Add this tag to current view)
    假如現在是在 tag three,你在 tag five 上按滑鼠右鍵,會在目前螢幕上顯示被加上 three 或 five 這兩個標籤的所有視窗。在 five 標籤上再按一次滑鼠右鍵,就會把標籤的選取狀態取消,也就是 tag five 代表的視窗又不顯示在目前螢幕上了。
    這相當於按快捷鍵 Win + Ctrl + 標籤數字 。
  • 在某個標籤上按 Win + 滑鼠右鍵 (Mod4 + Button3 on tag name)
    為焦點所在視窗加入/去除某個標籤 (Toggle this tag for client)
    這與 Win + 滑鼠左鍵 的差別在於,在某個標籤上按 Win + 滑鼠右鍵 來替焦點所在視窗加入新標籤時,仍保有原來的標籤,所以焦點所在視窗不會因為加入新標籤而消失在目前的螢幕上。
    所以 Win + 滑鼠右鍵 的使用時機,可看成是 - 想讓目前焦點所在視窗出現在其他 tag 代表的 workspaces,且還要讓這個視窗繼續出現在目前螢幕上。
    這相當於按快捷鍵 Win + Ctrl + Shift + 標籤數字 。
  • Button4, Button5 on tag name
    切換到前一個/下一個 tag。
  • 在 (layout symbol) 上按 Button1, Button3, Button4, Button5
    切換到前一個/下一個 layout。
  • 在 root window 上按 Button4, Button5
    切換到前一個/下一個 tag。
  • 在 client window 上按 Win + 滑鼠左鍵 (Mod4 + Button1)
    移動視窗。
  • 在 client window 上按 Win + 滑鼠?鍵 (Mod4 + Button2)
    Zoom 視窗。(我試不出這個功能)
  • 在 client window 上按 Win + 滑鼠右鍵 (Mod4 + Button3)
    改變視窗大小。
    實際使用時,如果視窗的管理是在 平鋪 (tiling) 的狀態,只能改變視窗的寬度。如果是在 浮動 (floating) 的狀態,就可以改變視窗的寬、高。

5. 預設的按鍵設定

awesome 提供了極豐富的快捷鍵。

5.1. 與狀態列相關

Win + F1 (Mod4 + F1)
用 awesome-menu 來讀 manual pages。
Win + F2 (Mod4 + F2)
用 awesome-menu 來執行程式。
Win + F3 (Mod4 + F3)
用 awesome-menu 來 ssh 到一台主機去。
Win + b (Mod4 + b)
開啟/關閉狀態列 (Toggle statusbar)
所謂的狀態列,就是指螢幕上方的標籤以及顯示目前開啟的視窗的地方。

5.2. 開始使用/離開/重新啟動 awesome

Win + Return (Mod4 + Return)
開啟 X terminal emulator。
Win + Shift + q (Mod4 + Shift + q)
離開 awesome (Quit awesome)。
Win + Ctrl + r (Mod4 + Control + r)
重新啟動 awesome (Restart awesome)。

5.3. 切換焦點

Win + j (Mod4 + j)
將焦點切換到下一個視窗 (Focus next client)。
Win + k (Mod4 + k)
將焦點切換到前一個視窗 (Focus previous client)。

5.4. 切換視野

Win + Left (Mod4 + Left)
看上一個標籤 (View previous tag)。
Win + Right (Mod4 + Right)
看下一個標籤 (View next tag)。
Win + 0-9 (Mod4 + 0-9)
切換到 tag 0-9 (Switch to tag 1-9, 0 for all)。0 代表顯示所有的視窗。
Win + Esc (Mod4 + Escape)
看先前選取的標籤 (View previously selected tag)。可在之前/目前所在的標籤之間切換。
Win + Control + j (Mod4 + Control + j)
將焦點切換到下一個螢幕 (Focus next screen)。
Win + Control + k (Mod4 + Control + k)
將焦點切換到上一個螢幕 (Focus previous screen)。

5.5. 移動視窗

Win + Shift + j (Mod4 + Shift + j)
將目前視窗與下一個視窗交換位置 (Switch client with next client)。
Win + Shift + l (Mod4 + Shift + k)
將目前視窗與前一個視窗交換位置 (Switch client with previous client)。

5.6. 視窗管理

Win + Shift + c (Mod4 + Shift + c)
關掉視窗 (Kill client)。
Win + Ctrl + 0-9 (Mod4 + Control + 0-9)
將標籤為 [0-9] 的視窗顯示在螢幕上 (Toggle tag view)。
可想成,要控制 (Control) 標籤為 [0-9] 的視窗 (Win)。
Win + Shift + 0-9 (Mod4 + Shift + 0-9)
給某個視窗加上標籤 (Tag client with tag)。
按下去後,視窗會消失在目前螢幕上,跑到新的標籤去,其實也就是把焦點所在的視窗搬到指定的標籤去。相當於在標籤上按 Win + 滑鼠左鍵 。
Win + Shift + Ctrl + 0-9 (Mod4 + Shift + Ctrl + 0-9)
為焦點所在視窗 加上/去掉 標籤 (Toggle tag on client)。
按下去後,視窗仍在目前螢幕上,不會消失,相當於在某個標籤上按 Win + 滑鼠右鍵 。

5.7. 切換版面配置

Win + 空白鍵 (Mod4 + space)
切換到下一個 layout。
Win + Shift + 空白鍵 (Mod4 + Shift + space)
切換到前一個 layout。

5.8. 調整版面配置區塊的大小

Win + h (Mod4 + h)
減少 主視窗區 5% 的高/寬度 (Decrease master width factor by 5%)。
Win + l (Mod4 + l)
增加 主視窗區 5% 的高/寬度 (Increase master width factor by 5%)。
Win + m (Mod4 + m)
將 client 設定成最大化 (Set client maximized)。
再按一次會回復原來大小。
Win + Ctrl + Enter (Mod4 + Control + Return)
Zoom client. (我試不出這個功能)

5.9. 調整版面配置的細節

Win + Shift + h (Mod4 + Shift + h)
增加一個 主視窗 (Increase number of master windows by 1)。
所謂 主視窗 ,依 Win + h 與 Win + l 的測試,是指多個視窗排在螢幕上時,上方或左方的完整區塊,依視窗排列方式而異,而非指佔用較大面積的視窗。預設狀態下,只有一個主視窗,此時,按 Win + h 或 Win + l 可以調整 主視窗 與 非主視窗 的大小。
Win + Shift + l (Mod4 + Shift + l)
減少一個 主視窗 (Decrease number of master windows by 1)。
Win + Ctrl + h (Mod4 + Control + h)
增加 非主視窗 的 column 數 (Increase number of columns for non-master windows by 1)
Note: 何謂 column? 這依視窗排列方式不同而異。
Win + Ctrl + l (Mod4 + Control + l)
減少 非主視窗 的 column 數 (Decrease number of columns for non-master windows by 1)
Win + Ctrl + 空白鍵 (Mod4 + Ctrl + Space)
設定視窗為浮動狀態 (Set client floating)。
也就是與一般 Window Manager 相同的視窗顯示方式,而非 Tiling 的方式。

2012年8月23日 星期四

Python and MSWord





1)安裝Active Python 
2)執行PythonWin
3)在工具列Tools > COM MakePy utility   出現清單後選擇Microsoft word 14.0 Object Library 進行build
4)開始可於PythonWin使用word物件功能

要使用Python控制MS Word,您需要先安裝win32com套件,這個套件可以到 http://sourceforge.net/projects/pywin32/ 找到。本文假設您已經正確安裝win32com及相關套件,所以將不再針對此部分多做說明。
毫無疑問的,您需要先import win32com模組才能進行Word的控制。
import win32com
from win32com.client import Dispatch, constants
接著,要讓我們的Python程式和MS Word建立起連結。
msword = Dispatch('Word.Application')
用Dispatch()的方式將會啟動MS Word。不過,如果您已經有執行MS Word,則此方式只會與現存的MS Word建立連結。如果您強烈希望能夠有一個新的MS Word程式出現,可用下面的方式:
msword = DispatchEx('Word.Application')
此時您會發現畫面上沒有任何MS Word出現,其實他已經在背後執行了。您可以透過工作管理員來查看是否有一個名為"WINWORD.EXE"的Process。不產生畫面的好處是您可 以在背景來處理您要進行的工作。如果您想要看看到底是不是真的有成功的啟動MS Word,請設定Visible屬性。
msword.Visible = 1 # 1表示要顯示畫面,若為0則不顯示畫面。您可以隨時的更改此屬性。
除了不顯示畫面外,您也許還會希望不要顯示一些警告訊息。此時請設定DisplayAlerts屬性:
msword.DisplayAlerts = 0 # 1表示要顯示訊息,0則會隱藏訊息。
若您真的有把畫面叫出來,您或許會發現此時的畫面上是沒有任何文件開啟的。沒錯!前面的動作只是幫助我們啟動Word並且建立連結,接著我們就要來開啟文件了。我們可以開啟已經存在的文件,或者是新增一個空白文件。
doc  = msword.Documents.Open(FileName="xxx.doc") # 開啟一個名為xxx.doc的文件。
newDoc  = msword.Documents.Add()   # 開啟一個新的文件。
msword.Quit()      # 關閉MS Word.
當然,除了開啟檔案或新建文件,您也可以存檔或者控制這些文件。
docCnt  = msword.Documents.Count  # 取得目前開啟文件的數量。
doc  = msword.Documents[n]   # 取得第n個文件的物件,以便後面的控制。
doc.Activate()     # 將文件設定為主要工作文件。
doc.PrintOut()     # 列印文件
doc.Save()     # 存檔
doc.SaveAs('xxx.doc')    # 另存新檔
doc.Undo(n)     # 回復前n次的動作
取得與文件的聯繫,接著我們可以對他進行編輯。不過,我們要能夠先取得編輯的控制權。透過Document的Range()函式,我們可以取得MS Word的Range物件。
range = doc.Range(0, 0) # 取得Range物件,範圍為文件的最開頭。
range = doc.Range()  # 取得Range物件,範圍為文件的最尾端。
range = doc.Range(doc.Content.Start, doc.Content.End) # 取得Range物件,範圍整份文件。
有了Range物件,我們就可以開始進行編輯了。
range.InsertBefore('在range前面插入的文字')
range.InsertAfter('在range後面插入的文字')
select = range.Select()  # 將range的範圍全部選取。並且取得Selection物件。
如果要設定Style,可以透過range物件的Style屬性來設定。
range.Style = constants.wdStyleHeading1  # 設定style為Heading 1
range.Style = constants.wdStyleHeading2  # 設定style為Heading 2
range.Style = constants.wdStyleHeading3  # 設定style為Heading 3
range.Style = constants.wdStyleHeading4  # 設定style為Heading 4
range.Style = constants.wdStyleHeading5  # 設定style為Heading 5
range.Style = constants.wdStyleHeading6  # 設定style為Heading 6
range.Style = constants.wdStyleHeading7  # 設定style為Heading 7
range.Style = constants.wdStyleHeading8  # 設定style為Heading 8
range.Style = constants.wdStyleHeading9  # 設定style為Heading 9
range.ParagraphFormat.Alignment = constants.wdAlignParagraphLeft # 設定段落為靠左
range.ParagraphFormat.Alignment = constants.wdAlignParagraphRight # 設定段落為靠右
range.ParagraphFormat.Alignment = constants.wdAlignParagraphCenter # 設定段落為置中
range.ParagraphFormat.Alignment = constants.wdAlignParagraphJustify # 設定段落為左右對齊
range.Style.Font.Name = "Arial"   # 設定字型為Arial
range.Style.Font.Name = "Time New Roman" # 設定字型為Time New Roman
range.Style.Font.Name = "標楷體"       # 設定字型為標楷體
range.Style.Font.Color = 0xFF0000  # 設定字型的顏色為Blue
range.Style.Font.Color = 0x00FF00  # 設定字型的顏色為Green
range.Style.Font.Color = 0x0000FF  # 設定字型的顏色為Red
range.Style.Font.Bold = 1   # 設定字型為粗體字
range.Style.Font.Italic = 1   # 設定字型為斜體字
range.Style.Font.Underline = 1   # 為字型加底線
range.Style.Font.Shadow = 1   # 為字型加陰影
range.Style.Font.Outline = 1   # 為字型加外框
如果要插入一個表格,可以用下面的方式來做。
table = doc.Tables.Add(range, 3, 4)   # 新增一個3x4表格
table.Cell(1,1).Range.InsertAfter('Some text')  # 新增文字到cell(1,1)
table.Cell(1,1).Range.Font.Name = "Arial"  # 設定字型為Arial
table.Cell(1,1).Range.Font.Color = 0xFF0000  # 設定字型為blue
table.Rows.Add()     # 新增一個Row
table.Columns.Add()     # 新增一個Column

2012年8月11日 星期六

python decorators三種寫法:decorator with arguments(class),decorator without arguments(class),decorator function with arguments

參考來源:http://www.artima.com/weblogs/viewpost.jsp?thread=240845


Decorators without Arguments(class)

注意事項:
1)decorator的__init__(self,f)必須傳入被修飾的函數f
2)decorator的__call__(self,*args)必須傳入被修飾的函數f的參數
3)執行到@decoratorWithoutArguments 時觸發 decorator的__init__方法
4)呼叫sayHello函數時觸發decorator的__call__方法


class decoratorWithoutArguments(object):

    def __init__(self, f):
        """
        If there are no decorator arguments, the function
        to be decorated is passed to the constructor.
        """
        print "Inside __init__()"
        self.f = f

    def __call__(self, *args):
        """
        The __call__ method is not called until the
        decorated function is called.
        """
        print "Inside __call__()"
        self.f(*args)
        print "After self.f(*args)"

@decoratorWithoutArguments
def sayHello(a1, a2, a3, a4):
    print 'sayHello arguments:', a1, a2, a3, a4

print "After decoration"

print "Preparing to call sayHello()"
sayHello("say", "hello", "argument", "list")
print "After first sayHello() call"
sayHello("a", "different", "set of", "arguments")
print "After second sayHello() call"



執行結果:

Inside __init__()
After decoration
Preparing to call sayHello()
Inside __call__()
sayHello arguments: say hello argument list
After self.f(*args)

After first sayHello() call
Inside __call__()
sayHello arguments: a different set of arguments
After self.f(*args)
After second sayHello() call
________________________________________

Decorators with Arguments(class)

注意事項:
1) decorator的__init__(self,arg1,arg2,arg3)必須傳入decorator需要的參數數量
例如: @decoratorWithArguments("hello", "world", 42) 共有三個參數設定為arg1,arg2,arg3
2) decorator的__call__(self,f)方法必須傳入被修飾的函數f
3)執行到@decoratorWithArguments("hello", "world", 42)時觸發 decorator的__init__方法
4)呼叫sayHello函數時觸發decorator的__call__方法內部定義的wrapped_f(*args)函數



class decoratorWithArguments(object):

    def __init__(self, arg1, arg2, arg3):
        """
        If there are decorator arguments, the function
        to be decorated is not passed to the constructor!
        """
        print "Inside __init__()"
        self.arg1 = arg1
        self.arg2 = arg2
        self.arg3 = arg3

    def __call__(self, f):
        """
        If there are decorator arguments, __call__() is only called
        once, as part of the decoration process! You can only give
        it a single argument, which is the function object.
        """
        print "Inside __call__()"
        def wrapped_f(*args):
            print "Inside wrapped_f()"
            print "Decorator arguments:", self.arg1, self.arg2, self.arg3
            f(*args)
            print "After f(*args)"
        return wrapped_f

@decoratorWithArguments("hello", "world", 42)
def sayHello(a1, a2, a3, a4):
    print 'sayHello arguments:', a1, a2, a3, a4

print "After decoration"

print "Preparing to call sayHello()"
sayHello("say", "hello", "argument", "list")
print "after first sayHello() call"
sayHello("a", "different", "set of", "arguments")
print "after second sayHello() call"


執行結果:


Inside __init__()
Inside __call__()
After decoration
Preparing to call sayHello()
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: say hello argument list
After f(*args)
after first sayHello() call
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: a different set of arguments
After f(*args)
after second sayHello() call
_______________________________________________________



Decorator Functions with Decorator Arguments

注意事項:
1)decoratorFunctionWithArguments(arg1, arg2, arg3) 的參數arg1,arg2,arg3為了接收
@decoratorFunctionWithArguments("hello", "world", 42) 的參數"hello", "world", 42
2)decoratorFunctionWithArguments內部的wrap(f)函數在執行敘述行,參數f則是為了接收被修飾函數sayHello,並且wrap(f)在程式執行敘述@decoratorFunctionWithArguments("hello", "world", 42) 時觸發
3)呼叫sayHello("say", "hello", "argument", "list")函數時觸發
decoratorFunctionWithArgument內的wrapped_f(*arg)函數


def decoratorFunctionWithArguments(arg1, arg2, arg3):
    def wrap(f):
        print "Inside wrap()"
        def wrapped_f(*args):
            print "Inside wrapped_f()"
            print "Decorator arguments:", arg1, arg2, arg3
            f(*args)
            print "After f(*args)"
        return wrapped_f
    return wrap

@decoratorFunctionWithArguments("hello", "world", 42)
def sayHello(a1, a2, a3, a4):
    print 'sayHello arguments:', a1, a2, a3, a4

print "After decoration"

print "Preparing to call sayHello()"
sayHello("say", "hello", "argument", "list")
print "after first sayHello() call"
sayHello("a", "different", "set of", "arguments")
print "after second sayHello() call"
執行結果:

with 與 __enter__(),__exit__(),上下文管理器



class Context(object):
    def __init__(self): #物件初始化時執行此方法
        print '__init__()'
    def __enter__(self):#進入with區塊後執行此方法
        print '__enter__()'
        return self
    def __exit__(self, exc_type, exc_val,exc_tb):#離開敘述區塊執行此方法
        print '__exit__()'

with Context():
    print 'Doing work in the context' #敘述區塊



執行結果
>>> 
__init__()
__enter__()
Doing work in the context
__exit__()
_________________________________________________________________

class WithinHello(object):
    def __init__(self, context):
        print 'WithinHello.__init__(%s)' %context
    def do_something(self):
        print 'WithinHello.do_something()'
    def __del__(self):
        print 'WithinHello.__del__'

class Hello(object):
    def __init__(self):
        print 'Hello.__init__()'
    def __enter__(self):
        print 'Hello.__enter__()'
        return WithinHello(self)
    def __exit__(self, exc_type, exc_val,exc_tb):
        print 'Hello.__exit__()'
  
with Hello() as c:
    c.do_something() #此時c為WithinHello的物件





>>>
Hello.__init__()
Hello.__enter__()
WithinHello.__init__(<__main__.Hello object at 0x0000000001CF9FD0>)
WithinHello.do_something()
Hello.__exit__()

_________________________________________________________________

class Context(object):
    def __init__(self, handle_error):
        print '__init__(%s)' % handle_error
        self.handle_error = handle_error
    def __enter__(self):
        print '__enter__()'
        return self
    def __exit__(self, exc_type, exc_val,exc_tb):
        print '__exit__()'
        print ' exc_type =', exc_type
        print ' exc_val  =', exc_val
        print ' exc_tb   =', exc_tb
        return self.handle_error 
        #如果上下文管理器可以處理這個異常,__exit__() 應當返回一個true值來指示不需要傳播這個異       常。如果返回false,就會導致__exit__()返回後重新拋出這個異常。

with Context(True):
    raise RuntimeError('error message handled')
print

with Context(False):
    raise RuntimeError('error message propagated')




>>> 
__init__(True)
__enter__()
__exit__()
 exc_type = <type 'exceptions.RuntimeError'>
 exc_val  = error message handled
 exc_tb   = <traceback object at 0x0000000002AB5B48>

__init__(False)
__enter__()
__exit__()
 exc_type = <type 'exceptions.RuntimeError'>
 exc_val  = error message propagated
 exc_tb   = <traceback object at 0x0000000002AB5D08>

Traceback (most recent call last):
  File "D:/python26/contextErrorHandle.py", line 20, in <module>
    raise RuntimeError('error message propagated')
RuntimeError: error message propagated
_________________________________________________________________

總和所有重要功能的程式碼


#-*- coding:utf8 -*-
#myContextManager.py

class withinContext(object):
    def __init__(self,context):
        #必定需要使用兩個參數self,context
        #其中withinContext中__init__方法的context參數用以接收
        #myContext中__enter__方法的return withinContext(self)敘述式的self參數
        print 'withinContext.__init__(%s)'%context
    def __del__(self):
        print 'withinContext.__del__()'
    def do_something(self):
        print 'withinContext.do_something()'

class myContext(object):
    def __init__(self,handle_error):
        print "myContext.__init__(%s)"%handle_error
        self.handle_error = handle_error
    def __enter__(self):
        print "myContext.__enter__()"
        return withinContext(self)
    def __exit__(self, exc_type, exc_val,exc_tb): #必定需要使用四個參數self,exc_type,exc_val,exc_tb
        print "myContext.__exit__()"
        print "exc_type:",exc_type
        print "exc_val :",exc_val
        print "exc_tb  :",exc_tb
        return self.handle_error #__exit__()方法若回傳True代表不傳播異常 若回傳False則代表傳播異常


with myContext(True) as c:
    c.do_something()
    raise RuntimeError('error message propagated.')