"""""""""""""""""""""""""""""""""""有限狀態機裡的巢狀類別States可以定義所有的狀態。繼承這個有限狀態機的類別需要覆寫StateProcess方法,該方法就是回傳狀態機的所需狀態清單。如此一來,使用上僅需要呼叫nextState方法,就能轉換狀態。
Library
"""""""""""""""""""""""""""""""""""
from abc import ABCMeta, abstractmethod # abstract class
from enum import Enum # constant
"""""""""""""""""""""""""""""""""""
Class
"""""""""""""""""""""""""""""""""""
## Avoids having to specify the value for each enumeration member.
class AutoNumber(Enum):
## Override.
def __new__(cls):
value = len(cls.__members__) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
## Finite state machine.
class FSM(object, metaclass = ABCMeta):
## State definition.
class States(AutoNumber):
Initial = ()
Ready = ()
Idle = ()
Start = ()
Pause = ()
Stop = ()
SendingRequest = ()
SentRequest = ()
ReceivingResponse = ()
ReceivedResponse = ()
Creating = ()
Created = ()
Storing = ()
Stored = ()
Reading = ()
Read = ()
Writing = ()
Wrote = ()
Removing = ()
Removed = ()
Parsing = ()
Parsed = ()
Finished = ()
_Error = () # This is not public state.
_Except = () # This is not public state.
## Constructor.
def __init__(self):
self._stateProcess = self.StateProcess
self.__stateIndex = 0
self._state = self._stateProcess[0]
## Get state process definition.
# @details The state process could be a cycle. For example: [FSM.State.Initial, FSM.State.SendingRequest, FSM.State.ReceivingResponse, FSM.State.SendingRequest, FSM.State.Finished].
# @note If there are two cycles with the same states, it is a wrong state process definition.
# @return A list of state.
@property
@abstractmethod
def StateProcess(self):
"""Get state process definition."""
return [FSM.States.Initial, FSM.States.Finished]
## Get state.
# @return Current state.
@property
def State(self):
"""Get current state."""
return self._state
## Get state before except.
# @return The last state.
@property
def StateBeforeExcept(self):
"""Get previous state before except/error."""
return self._stateProcess[self.__stateIndex]
## Process definition
# @param skip - number of state to be passes. (optional)
# @param end - if true, the latest state sets the ending state; otherwise, it sets the next state. (optional)
# @param error - if true, the state sets the error state. (optional)
def nextState(self, skip = 0, end = False, error = False):
# avoid to reboot
if self.isStopped():
return
# The highest priority
if error is True:
self._state = FSM.States._Error
return
# check parameters
if skip < 0:
self._state = FSM.States._Except
return
if end is True:
self.__stateIndex = len(self._stateProcess) - 1
self._state = self._stateProcess[self.__stateIndex]
return
self.__stateIndex = min(self.__stateIndex + 1 + skip, len(self._stateProcess) - 1)
# check cycle
i = self._stateProcess.index(self._stateProcess[self.__stateIndex])
if i != self.__stateIndex:
self.__stateIndex = i
self._state = self._stateProcess[self.__stateIndex]
## Reset state to the initial process.
def resetState(self):
self.__stateIndex = 0
self._state = self._stateProcess[0]
## Check if state is end or not.
# @retval true if the state is the end.
# @retval false otherwise.
def isEndState(self):
return self._state == self._stateProcess[-1]
## Check if state is except or not.
# @retval true if the state is the except state.
# @retval false otherwise.
def isExceptState(self):
return self._state == FSM.States._Except
## Check if state is error or not.
# @retval true if the state is the error state.
# @retval false otherwise.
def isErrorState(self):
return self._state == FSM.States._Error
## Check if the FSM is stopped or not.
# @retval true if the FSM is stopped.
# @retval false otherwise.
def isStopped(self):
return self.isEndState() or self.isExceptState() or self.isErrorState()
2014年7月23日 星期三
Python - 有限狀態機
在撰寫模組時,因為使用有限狀態機來記錄每個模組的運作情況,所以寫了一個有限狀態機的類別供繼承用。
Python - 抽象類別
Python的library中,有東西能協助建立抽象類別與抽象方法。
from abc import ABCMeta, abstractmethod # abstract class如此一來,繼承base類別就一定要覆寫foo方法。
class base(metaclass = ABCMeta):
@abstractmethod
def foo(self):
pass
Python - 不確定參數與屬性
Python傳遞不確定的參數值:
opt = 1
args = (True, "hello")
kwargs = {"data" : "world", "size" : 8}
在使用繼承類別時,如果有多種形態的繼承類別,利用傳遞不確定的參數值,可以做到彈性的呼叫。
Python也可以傳遞不確定的屬性給物件:
def foo1(opt, *args, **kwargs):在這裡,opt是確定的參數,不確定的參數有args和kwargs,args的資料型態為tuple, kwargs的資料型態為dict。
# expressions
foo1(1, True, "hello", data = "world", size = 8)上面這一行呼叫了foo1,並傳遞五個參數值,進入foo1後,參數分別為:
opt = 1
args = (True, "hello")
kwargs = {"data" : "world", "size" : 8}
在使用繼承類別時,如果有多種形態的繼承類別,利用傳遞不確定的參數值,可以做到彈性的呼叫。
Python也可以傳遞不確定的屬性給物件:
class base():利用setattr和getattr這兩個內建函式,做到動態賦予物件屬性。這種寫法也是為了彈性設計。
def setParameters(self, **params):
for key, value in params.items():
setattr(self, key, value)
def run(self, out, **options):
data = getattr(self, "data", "")
length = getattr(self, "len", 0)
Python - decorator運用(2)
在撰寫函式時,因為python的特性,不會去檢查回傳值的資料型態是否正確,也不會去檢查是否遺漏回傳值,這對於撰寫複雜一點的函式容易有疏忽的地方,這時候就能靠decorator做一些協助,例如遺漏回傳值時補上預設回傳值,或者回傳值型態錯誤時丟出例外錯誤。
import functools
## Check return type and value.
# @details The return value could be one following situation:
# 1. value type is specified in the \a cls;
# 2. None;
# 3. value type is not specified and not None.
#
# In the 1st situation, return original value.
# In the 2nd situation, if allow_none is true, return None; otherwise, return \a default.
# In the 3rd situation, raise SyntaxError.
# @param default is the default return value.
# @param cls is the specified return value type.
# @param allow_none - if true, the return value could be None; otherwise, the return value must be assigned.
# @exception SyntaxError
def checkReturn(default, allow_type = None, allow_none = False):
def check_decorator(function):
def decorator_wrapper(*args, **kwargs):
result = function(*args, **kwargs)
cls = allow_type
try:
if allow_type is None:
cls = (type(default),)
elif not issubclass(allow_type, tuple):
cls = (allow_type,)
except Exception as e:
raise
if type(result) in cls:
pass
elif result is None:
if allow_none:
pass
else:
result = default
else:
raise SyntaxError("The type of return value {0} is not in {1}.".format(result, cls))
return result
return decorator_wrapper
return check_decorator
Python - decorator運用(1)
在trace程式碼的時候,尤其是多執行緒的程式碼,想知道函式的呼叫情況,此時會記錄函式的進出資訊。在python,可以使用decorator幫助記錄。
另外,有時需要記錄函式的執行時間,一樣可以使用decorator幫助記錄。
在這裡的logger是指logging.logger。
decorator的使用方式為:
import functools
import time
def logFunc(logger = None):
def log_decorator(function):
@functools.wraps(function)
def decorator_wrapper(*args, **kwargs):
if logger is None:
print("{2} [Debug] Enter {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
result = function(*args, **kwargs)
print("{2} [Debug] Exit {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
else:
logger.debug("Enter {0}.{1}".format(function.__module__, function.__name__))
result = function(*args, **kwargs)
logger.debug("Exit {0}.{1}".format(function.__module__, function.__name__))
return result
return decorator_wrapper
return log_decorator
另外,有時需要記錄函式的執行時間,一樣可以使用decorator幫助記錄。
import functools
import time
def logTime(logger = None):
def time_decorator(function):
def decorator_wrapper(*args, **kwargs):
start = time.time()
result = function(*args, **kwargs)
end = time.time()
if logger is None:
print("{3} [Debug] {0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start, time.asctime()))
else:
logger.debug("{0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start))
return result
return decorator_wrapper
return time_decorator
在這裡的logger是指logging.logger。
decorator的使用方式為:
@logFunc(logger)
def foo1():
# expressions
@logTime(logger)
def foo2():
# expressions
2014年5月28日 星期三
C++ - 整數運算之溢位偵測
整數運算中,最容易產生溢位問題的估計是階層運算。設計一個factorial遞回函式來運算階層,輸入是一個整數N,輸出則為N!的結果,輸入和輸出的整數資料型態一致,假設使用unsigned int作為整數資料型態,該factorial函式表示如下:
如果是兩個整數相加,溢位會多增加一個位元,可以檢查兩個整數相加是否會有進位現象,進位後會不會超出資料型態的位元數,來判斷相加會不會產生溢位。
可是階層運算是乘法運算,無法用相加的溢位判斷方式,而要用其他的方式判斷。
方式一:溢位旗標的判斷。因為暫存器的關係,僅適用於int、unsigned int等32位元的整數資料型態,若用於其他位元數的整數資料型態會判斷錯誤。
方法二就已經足夠使用,方法三就留給以後需要的時候再來實作。
unsigned int factorial(unsigned int N)這是很簡單的一個寫法,用unsigned int是因為階層的定義要求為正整數或0。這個寫法並沒考量到溢位問題,當輸入的N為13時,就會產生溢位問題。
{
return (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
}
如果是兩個整數相加,溢位會多增加一個位元,可以檢查兩個整數相加是否會有進位現象,進位後會不會超出資料型態的位元數,來判斷相加會不會產生溢位。
可是階層運算是乘法運算,無法用相加的溢位判斷方式,而要用其他的方式判斷。
方式一:溢位旗標的判斷。因為暫存器的關係,僅適用於int、unsigned int等32位元的整數資料型態,若用於其他位元數的整數資料型態會判斷錯誤。
unsigned int factorial(unsigned int N)方法二:除法運算檢查。適用各種整數資料型態。
{
unsigned int product = 0;
product = (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
__asm jo overflowed;
if (0)
{
overflowed:
throw(std::out_of_range("Overflowed"));
}
return product;
}
int factorial(int N)方法三:自訂BigInteger的資料型態。 BigInteger的數字是使用字元陣列來表示,運算採取字元陣列的方式做運算,加減乘除也需要自訂,因為是用字元陣列來表示一個數字,所以該數字理論上可以無限大(實際上會受限字元陣列所能表示的最大長度)。
{
int product = 0;
if (N < 0) // 限定N為正整數或0
{
throw(std::out_of_range("Negative integer"));
}
if (N == 0 || N == 1)
{
product = 1;
}
else
{
int multiplicand = factorial(N - 1);
product = N * multiplicand;
if (product / N != multiplicand) throw(std::out_of_range("Overflowed"));
}
return product;
}
方法二就已經足夠使用,方法三就留給以後需要的時候再來實作。
2014年5月8日 星期四
Doxygen - 圖形化類別關聯性
Doxygen是一套利用程式註解的方式,建立出程式說明文件的軟體。
Graphviz是一套利用命令和參數畫出關係圖的軟體。
Doxygen產出文件時,可以透過參數設定,使用Graphviz來繪圖。操作步驟為:
最後,建立完文件,在類別分類中就可以看到關係圖了。
Graphviz是一套利用命令和參數畫出關係圖的軟體。
Doxygen產出文件時,可以透過參數設定,使用Graphviz來繪圖。操作步驟為:
最後,建立完文件,在類別分類中就可以看到關係圖了。
訂閱:
文章 (Atom)