最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用Python創(chuàng)建聲明性迷你語(yǔ)言的教程

 更新時(shí)間:2015年04月13日 16:23:46   投稿:goldensun  
這篇文章主要介紹了用Python創(chuàng)建聲明性迷你語(yǔ)言的教程,本文來自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下

大多數(shù)程序員考慮編程時(shí),他們都要設(shè)想用于編寫應(yīng)用程序的 命令式樣式和技術(shù)。最受歡迎的通用編程語(yǔ)言(包括 Python 和其它面向?qū)ο蟮恼Z(yǔ)言)在樣式上絕大多數(shù)都是命令式的。另一方面,也有許多編程語(yǔ)言是 聲明性樣式,包括函數(shù)語(yǔ)言和邏輯語(yǔ)言,還包括通用語(yǔ)言和專用語(yǔ)言。

讓我們列出幾個(gè)屬于各個(gè)種類的語(yǔ)言。許多讀者已經(jīng)使用過這些工具中的許多工具,但不見得考慮過它們之間的種類差別。Python、C、C++、Java、Perl、Ruby、Smalltalk、Fortran、Basic 和 xBase 都是簡(jiǎn)單的命令式編程語(yǔ)言。其中,一些是面向?qū)ο蟮模侵皇墙M織代碼和數(shù)據(jù)的問題,而非基本編程樣式的問題。使用這些語(yǔ)言,您 命令程序執(zhí)行指令序列:把某些數(shù)據(jù) 放入(put)變量中;從變量中 獲?。╢etch)數(shù)據(jù); 循環(huán)(loop)一個(gè)指令塊 直到(until)滿足了某些條件; 如果(if)某個(gè)命題為 true,那么就進(jìn)行某些操作。所有這些語(yǔ)言的一個(gè)妙處在于:便于用日常生活中熟悉的比喻來考慮它們。日常生活都是由做事、選擇、再做另一件事所組成的,期間或許會(huì)使用一些工具。可以簡(jiǎn)單地將運(yùn)行程序的計(jì)算機(jī)想象成廚師、瓦匠或汽車司機(jī)。

諸如 Prolog、Mercury、SQL、XSLT 這樣的語(yǔ)言、EBNF 語(yǔ)法和各種格式的真正配置文件,都 聲明某事是這種情況,或者應(yīng)用了某些約束。函數(shù)語(yǔ)言(比如 Haskell、ML、Dylan、Ocaml 和 Scheme)與此相似,但是它們更加強(qiáng)調(diào)陳述編程對(duì)象(遞歸、列表,等等)之間的內(nèi)部(函數(shù))關(guān)系。我們的日常生活(至少在敘事質(zhì)量方面)沒有提供對(duì)這些語(yǔ)言的編程構(gòu)造的直接模擬。然而,對(duì)于那些可以用這些語(yǔ)言進(jìn)行描述的問題來說,聲明性描述 遠(yuǎn)遠(yuǎn)比命令式解決方案來得簡(jiǎn)明且不易出錯(cuò)。例如,請(qǐng)研究下面這個(gè)線性方程組:
清單 1. 線性方程式系統(tǒng)樣本

10x + 5y - 7z + 1 = 0
17x + 5y - 10z + 3 = 0
5x - 4y + 3z - 6 = 0

這是個(gè)相當(dāng)漂亮的說明對(duì)象(x、y 和 z)之間幾個(gè)關(guān)系的簡(jiǎn)單表達(dá)式。在現(xiàn)實(shí)生活中您可能會(huì)用不同的方式求出這些答案,但是實(shí)際上用筆和紙“求解 x”很煩,而且容易出錯(cuò)。從調(diào)試角度來講,用 Python 編寫求解步驟或許會(huì)更糟糕。

Prolog 是與邏輯或數(shù)學(xué)關(guān)系密切的語(yǔ)言。使用這種語(yǔ)言,您只要編寫您知道是正確的語(yǔ)句,然后讓應(yīng)用程序?yàn)槟贸鼋Y(jié)果。語(yǔ)句不是按照特定的順序構(gòu)成的(和線性方程式一樣,沒有順序),而且您(程序員或用戶)并不知道得出的結(jié)果都采用了哪些步驟。例如:
清單 2. family.pro Prolog 樣本

/* Adapted from sample at:
<http://www.engin.umd.umich.edu/CIS/course.des/cis479/prolog/>
This app can answer questions about sisterhood & love, e.g.:
# Is alice a sister of harry?
?-sisterof( alice, harry )
# Which of alice' sisters love wine?
?-sisterof( X, alice ), love( X, wine)
*/
sisterof( X, Y ) :- parents( X, M, F ),
          female( X ),
          parents( Y, M, F ).
parents( edward, victoria, albert ).
parents( harry, victoria, albert ).
parents( alice, victoria, albert ).
female( alice ).
loves( harry, wine ).
loves( alice, wine ).

它和 EBNF(擴(kuò)展巴科斯范式,Extended Backus-Naur Form)語(yǔ)法聲明并不完全一樣,但是實(shí)質(zhì)相似。您可以編寫一些下面這樣的聲明:
清單 3. EBNF 樣本

word    := alphanums, (wordpunct, alphanums)*, contraction?
alphanums  := [a-zA-Z0-9]+
wordpunct  := [-_]
contraction := "'", ("clock"/"d"/"ll"/"m"/"re"/"s"/"t"/"ve")

如果您遇到一個(gè)單詞而想要表述其看上去 可能會(huì)是什么,而實(shí)際上又不想給出如何識(shí)別它的序列指令,上面便是個(gè)簡(jiǎn)練的方法。正則表達(dá)式與此相似(并且事實(shí)上它能夠滿足這種特定語(yǔ)法產(chǎn)品的需要)。

還有另一個(gè)聲明性示例,請(qǐng)研究描述有效 XML 文檔方言的文檔類型聲明:
清單 4. XML 文檔類型聲明

<!ELEMENT dissertation (chapter+)>
<!ELEMENT chapter (title, paragraph+)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT paragraph (#PCDATA | figure)+>
<!ELEMENT figure EMPTY>

和其它示例一樣,DTD 語(yǔ)言不包含任何有關(guān)如何識(shí)別或創(chuàng)建有效 XML 文檔的指令。它只描述了如果文檔存在,那它會(huì)是怎么樣的。聲明性語(yǔ)言采用虛擬語(yǔ)氣。
Python 作為解釋器 vs Python 作為環(huán)境

Python 庫(kù)可以通過兩種截然不同的方式中的一種來利用聲明性語(yǔ)言?;蛟S更為常用的技術(shù)是將非 Python 聲明性語(yǔ)言作為數(shù)據(jù)來解析和處理。應(yīng)用程序或庫(kù)可以讀入外部來源(或者是內(nèi)部定義的但只用作“blob”的字符串),然后指出一組要執(zhí)行的命令式步驟,這些步驟在某種形式上與那些外部聲明是一致的。本質(zhì)上,這些類型的庫(kù)是“數(shù)據(jù)驅(qū)動(dòng)的”系統(tǒng);聲明性語(yǔ)言和 Python 應(yīng)用程序執(zhí)行或利用其聲明的操作之間有著概念和范疇差別。事實(shí)上,相當(dāng)普遍的一點(diǎn)是,處理那些相同聲明的庫(kù)也被用來實(shí)現(xiàn)其它編程語(yǔ)言。

上面給出的所有示例都屬于第一種技術(shù)。庫(kù) PyLog 是 Prolog 系統(tǒng)的 Python 實(shí)現(xiàn)。它讀取像樣本那樣的 Prolog 數(shù)據(jù)文件,然后創(chuàng)建 Python 對(duì)象來對(duì) Prolog 聲明 建模。EBNF 樣本使用專門變體 SimpleParse ,這是一個(gè) Python 庫(kù),它將這些聲明轉(zhuǎn)換成可以被 mx.TextTools 所使用的狀態(tài)表。 mx.TextTools 自身是 Python 的擴(kuò)展庫(kù),它使用底層 C 引擎來運(yùn)行存儲(chǔ)在 Python 數(shù)據(jù)結(jié)構(gòu)中的代碼,但與 Python 本質(zhì)上幾乎沒什么關(guān)系。對(duì)于這些任務(wù)而言,Python 是極佳的 粘合劑,但是粘合在一起的語(yǔ)言與 Python 差別很大。而且,大多數(shù) Prolog 實(shí)現(xiàn)都不是用 Python 編寫的,這和大多數(shù) EBNF 解析器一樣。

DTD 類似于其它示例。如果您使用象 xmlproc 這樣的驗(yàn)證解析器,您可以利用 DTD 來驗(yàn)證 XML 文檔的方言。但是 DTD 的語(yǔ)言并不是 Python 式的, xmlproc 只將它用作需要解析的數(shù)據(jù)。而且,已經(jīng)用許多編程語(yǔ)言編寫過 XML 驗(yàn)證解析器。XSLT 轉(zhuǎn)換與此相似,也不是特定于 Python 的,而且像 ft.4xslt 這樣的模塊只將 Python 用作“粘合劑”。

雖然上面的方法和上面所提到的工具(我一直都在使用)都沒什么 不對(duì),但如果 Python 本身是聲明性語(yǔ)言的話,那么它可能會(huì)更精妙,而且某些方面會(huì)表達(dá)得更清晰。如果沒有其它因素的話,有助于此的庫(kù)不會(huì)使程序員在編寫一個(gè)應(yīng)用程序時(shí)考慮是否采用兩種(或更多)語(yǔ)言。有時(shí),依靠 Python 的自省能力來實(shí)現(xiàn)“本機(jī)”聲明,既簡(jiǎn)單又管用。

自省的魔力

解析器 Spark 和 PLY 讓用戶 用 Python 來聲明 Python 值,然后使用某些魔法來讓 Python 運(yùn)行時(shí)環(huán)境進(jìn)行解析配置。例如,讓我們研究一下與前面 SimpleParse 語(yǔ)法等價(jià)的 PLY 語(yǔ)法。 Spark 類似于下面這個(gè)示例:
清單 5. PLY 樣本

tokens = ('ALPHANUMS','WORDPUNCT','CONTRACTION','WHITSPACE')
t_ALPHANUMS = r"[a-zA-Z0-0]+"
t_WORDPUNCT = r"[-_]"
t_CONTRACTION = r"'(clock|d|ll|m|re|s|t|ve)"
def t_WHITESPACE(t):
  r"\s+"
  t.value = " "
  return t
import lex
lex.lex()
lex.input(sometext)
while 1:
  t = lex.token()
  if not t: break

我已經(jīng)在我即將出版的書籍 Text Processing in Python 中編寫了有關(guān) PLY 的內(nèi)容,并且在本專欄文章中編寫了有關(guān) Spark 的內(nèi)容(請(qǐng)參閱 參考資料以獲取相應(yīng)鏈接)。不必深入了解庫(kù)的詳細(xì)信息,這里您應(yīng)當(dāng)注意的是:正是 Python 綁定本身配置了解析(在這個(gè)示例中實(shí)際是詞法分析/標(biāo)記化)。 PLY 模塊在 Python 環(huán)境中運(yùn)行以作用于這些模式聲明,因此就正好非常了解該環(huán)境。

PLY如何得知它自己做什么,這涉及到一些非常奇異的 Python 編程。起初,中級(jí)程序員會(huì)發(fā)現(xiàn)可以查明 globals() 和 locals() 字典的內(nèi)容。如果聲明樣式略有差異的話就好了。例如,假想代碼更類似于這樣:
清單 6. 使用導(dǎo)入的模塊名稱空間

import basic_lex as _
_.tokens = ('ALPHANUMS','WORDPUNCT','CONTRACTION')
_.ALPHANUMS = r"[a-zA-Z0-0]+"
_.WORDPUNCT = r"[-_]"
_.CONTRACTION = r"'(clock|d|ll|m|re|s|t|ve)"
_.lex()

這種樣式的聲明性并不差,而且可以假設(shè) basic_lex 模塊包含類似下面這樣的簡(jiǎn)單內(nèi)容:
清單 7. basic_lex.py

def lex():
  for t in tokens:
    print t, '=', globals()[t]

這會(huì)產(chǎn)生:

% python basic_app.py
ALPHANUMS = [a-zA-Z0-0]+
WORDPUNCT = [-_]
CONTRACTION = '(clock|d|ll|m|re|s|t|ve)

PLY 設(shè)法使用堆棧幀信息插入了導(dǎo)入模塊的名稱空間。例如:
清單 8. magic_lex.py

import sys
try: raise RuntimeError
except RuntimeError:
  e,b,t = sys.exc_info()
  caller_dict = t.tb_frame.f_back.f_globals
def lex():
  for t in caller_dict['tokens']:
    print t, '=', caller_dict['t_'+t]

這產(chǎn)生了與 basic_app.py 樣本所給輸出一樣的輸出,但是具有使用前面 t_TOKEN 樣式的聲明。

實(shí)際的 PLY 模塊中要比這更神奇。我們看到用模式 t_TOKEN 命名的標(biāo)記實(shí)際上可以是包含了正則表達(dá)式的字符串,或是包含了正則表達(dá)式文檔字符串和操作代碼的函數(shù)。某些類型檢查允許以下多態(tài)行為:
清單 9. polymorphic_lex

# ...determine caller_dict using RuntimeError...
from types import *
def lex():
  for t in caller_dict['tokens']:
    t_obj = caller_dict['t_'+t]
    if type(t_obj) is FunctionType:
      print t, '=', t_obj.__doc__
    else:
      print t, '=', t_obj

顯然,相對(duì)于用來玩玩的示例而言,真正的 PLY 模塊用這些已聲明的模式可以做更有趣的事,但是這些示例演示了其中所涉及的一些技術(shù)。

繼承的魔力

讓支持庫(kù)到處插入并操作應(yīng)用程序的名稱空間,這會(huì)啟用精妙的聲明性樣式。但通常,將繼承結(jié)構(gòu)和自省一起使用會(huì)使靈活性更佳。

模塊 gnosis.xml.validity 是用來創(chuàng)建直接映射到 DTD 產(chǎn)品的類的框架。任何 gnosis.xml.validity 類 只能用符合 XML 方言有效性約束的參數(shù)進(jìn)行實(shí)例化。實(shí)際上,這并不十分正確;當(dāng)只存在一種明確的方式可將參數(shù)“提升”成正確類型時(shí),模塊也可從更簡(jiǎn)單的參數(shù)中推斷出正確類型。

由于我已經(jīng)編寫了 gnosis.xml.validity 模塊,所以我傾向于思考其用途自身是否有趣。但是對(duì)于本文,我只想研究創(chuàng)建有效性類的聲明性樣式。與前面的 DTD 樣本相匹配的一組規(guī)則/類包括:
清單 10. gnosis.xml.validity 規(guī)則聲明

from gnosis.xml.validity import *
class figure(EMPTY):   pass
class _mixedpara(Or):   _disjoins = (PCDATA, figure)
class paragraph(Some):  _type = _mixedpara
class title(PCDATA):   pass
class _paras(Some):    _type = paragraph
class chapter(Seq):    _order = (title, _paras)
class dissertation(Some): _type = chapter

您可以使用以下命令從這些聲明中創(chuàng)建出實(shí)例:

ch1 = LiftSeq(chapter, ("1st Title","Validity is important"))
ch2 = LiftSeq(chapter, ("2nd Title","Declaration is fun"))
diss = dissertation([ch1, ch2])
print diss

請(qǐng)注意這些類和前面的 DTD 非常匹配。映射基本上是一一對(duì)應(yīng)的;除了有必要對(duì)嵌套標(biāo)記的量化和交替使用中介體之外(中介體名稱用前導(dǎo)下劃線標(biāo)出來)。

還要注意的是,這些類雖然是用標(biāo)準(zhǔn) Python 語(yǔ)法創(chuàng)建的,但它們也有不同尋常(且更簡(jiǎn)練)之處:它們沒有方法或?qū)嵗龜?shù)據(jù)。單獨(dú)定義類,以便從某框架繼承類,而該框架受到單一的類屬性限制。例如, <chapter> 是其它標(biāo)記序列,即 <title> 后面跟著一個(gè)或多個(gè) <paragraph> 標(biāo)記。但是為確保在實(shí)例中遵守約束,我們所需做的就是用這種簡(jiǎn)單的方式來 聲明chapter 類。

編寫像 gnosis.xml.validity.Seq 這樣的父類程序所涉及的主要“技巧”,就是在初始化期間研究 實(shí)例的 .__class__ 屬性。類 chapter 自身并不進(jìn)行初始化,因此調(diào)用其父類的 __init__() 方法。但是傳遞給父類 __init__() 的 self 是 chapter 的實(shí)例,而且 self 知道 chapter。為了舉例說明這一點(diǎn),下面列出了部分 gnosis.xml.validity.Seq 實(shí)現(xiàn):
清單 11. 類 gnosis.xml.validity.Seq

class Seq(tuple):
  def __init__(self, inittup):
    if not hasattr(self.__class__, '_order'):
      raise NotImplementedError, \
        "Child of Abstract Class Seq must specify order"
    if not isinstance(self._order, tuple):
      raise ValidityError, "Seq must have tuple as order"
    self.validate()
    self._tag = self.__class__.__name__

一旦應(yīng)用程序程序員試圖創(chuàng)建 chapter 實(shí)例,實(shí)例化代碼就檢查是否用所要求的 ._order 類屬性聲明了 chapter ,并檢查該屬性是否為所需的元組對(duì)象。方法 .validate() 要做進(jìn)一步的檢查,以確保初始化實(shí)例所用的對(duì)象屬于 ._order 中指定的相應(yīng)類。

何時(shí)聲明

聲明性編程樣式在聲明約束方面 幾乎一直比命令式或過程式樣式更直接。當(dāng)然,并非所有的編程問題都是關(guān)于約束的 - 或者說至少這并非總是自然定律。但是如果基于規(guī)則的系統(tǒng)(比如語(yǔ)法和推理系統(tǒng))可以進(jìn)行聲明性描述,那么它們的問題就比較容易處理了。是否符合語(yǔ)法的命令式驗(yàn)證很快就會(huì)變成非常復(fù)雜難懂的所謂“意大利面條式代碼”(spaghetti code),而且很難調(diào)試。模式和規(guī)則的聲明仍然可以更簡(jiǎn)單。

當(dāng)然,起碼在 Python 中,聲明規(guī)則的驗(yàn)證和增強(qiáng)總是會(huì)歸結(jié)為過程式檢查。但是把這種過程式檢查放在進(jìn)行了良好測(cè)試的庫(kù)代碼中比較合適。單獨(dú)的應(yīng)用程序應(yīng)該依靠由像 Spark 或 PLY 或 gnosis.xml.validity 這樣的庫(kù)所提供的更簡(jiǎn)單的聲明性接口。其它像 xmlproc 、 SimpleParse 或 ft.4xslt 這樣的庫(kù),盡管不是 用 Python進(jìn)行聲明的(Python 當(dāng)然適用于它們的領(lǐng)域),也能使用聲明性樣式。

相關(guān)文章

  • Python利用matplotlib實(shí)現(xiàn)餅圖繪制

    Python利用matplotlib實(shí)現(xiàn)餅圖繪制

    Pyplot作為Matplotlib的子庫(kù),提供了和MATLAB差不多的繪圖API。因此Pyplot作為常用的繪圖模塊,能很方便讓用戶繪制2D圖表。本文將為大家介紹如何利用Matplotlib繪制餅圖,感興趣的小伙伴可以了解一下
    2021-12-12
  • Python實(shí)現(xiàn)從線程獲取返回值

    Python實(shí)現(xiàn)從線程獲取返回值

    本文介紹了Python中線程的概念、創(chuàng)建線程的方法和在線程中獲取函數(shù)返回值的技巧,線程作為進(jìn)程中的執(zhí)行單元,可以實(shí)現(xiàn)程序的并發(fā)運(yùn)行,文章通過示例代碼展示了如何在Python中使用Thread類創(chuàng)建線程,并講解了在線程中傳遞參數(shù)和獲取返回值的方法
    2024-09-09
  • 利用python寫api接口實(shí)戰(zhàn)指南

    利用python寫api接口實(shí)戰(zhàn)指南

    api接口在我們開發(fā)中的重要性相信大家都這篇文章主要給大家介紹了關(guān)于利用python寫api接口實(shí)戰(zhàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • python計(jì)算一個(gè)序列的平均值的方法

    python計(jì)算一個(gè)序列的平均值的方法

    這篇文章主要介紹了python計(jì)算一個(gè)序列的平均值的方法,涉及Python遞歸遍歷與數(shù)學(xué)計(jì)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • 如何徹底解決Python中matplotlib不顯示中文的問題詳解(顯示方框)

    如何徹底解決Python中matplotlib不顯示中文的問題詳解(顯示方框)

    Matplotlib繪制圖像顯示中文的時(shí)候,中文會(huì)變成小方格子,下面這篇文章主要給大家介紹了關(guān)于如何徹底解決Python中matplotlib不顯示中文問題的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • 解決在pycharm運(yùn)行代碼,調(diào)用CMD窗口的命令運(yùn)行顯示亂碼問題

    解決在pycharm運(yùn)行代碼,調(diào)用CMD窗口的命令運(yùn)行顯示亂碼問題

    今天小編就為大家分享一篇解決在pycharm運(yùn)行代碼,調(diào)用CMD窗口的命令運(yùn)行顯示亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Python中用字符串調(diào)用函數(shù)或方法示例代碼

    Python中用字符串調(diào)用函數(shù)或方法示例代碼

    字符串作為python中常用的數(shù)據(jù)類型,掌握字符串的常用方法十分必要。下面這篇文章主要給大家介紹了關(guān)于Python中通過字符串調(diào)用函數(shù)或方法的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • 修改Python?pip下載包的默認(rèn)路徑詳細(xì)步驟記錄

    修改Python?pip下載包的默認(rèn)路徑詳細(xì)步驟記錄

    這篇文章主要介紹了如何修改pip的默認(rèn)安裝路徑以釋放C盤空間,特別是針對(duì)機(jī)器學(xué)習(xí)相關(guān)的大型包,可以將pip的安裝位置更改為其他目錄,需要的朋友可以參考下
    2025-03-03
  • python之Django自動(dòng)化資產(chǎn)掃描的實(shí)現(xiàn)

    python之Django自動(dòng)化資產(chǎn)掃描的實(shí)現(xiàn)

    這篇文章主要介紹了python之Django自動(dòng)化資產(chǎn)掃描的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • python使用pandas實(shí)現(xiàn)Excel轉(zhuǎn)換為CSV文件

    python使用pandas實(shí)現(xiàn)Excel轉(zhuǎn)換為CSV文件

    在數(shù)據(jù)處理和分析中,我們經(jīng)常需要將 Excel 文件轉(zhuǎn)換為 CSV 格式,這篇文章我們主要來介紹一下python如何使用pandas實(shí)現(xiàn)Excel轉(zhuǎn)換為CSV文件,希望對(duì)大家有所幫助
    2024-10-10

最新評(píng)論

保德县| 宽甸| 商南县| 塘沽区| 阳曲县| 南乐县| 和顺县| 台湾省| 宁强县| 清河县| 边坝县| 泽州县| 景洪市| 高邮市| 贵阳市| 永年县| 马鞍山市| 泸水县| 淅川县| 时尚| 开平市| 民勤县| 襄垣县| 台南市| 巍山| 平安县| 桦甸市| 龙州县| 浪卡子县| 沈丘县| 中牟县| 南靖县| 耒阳市| 安吉县| 扬州市| 买车| 绵竹市| 临城县| 安阳市| 永济市| 诸城市|