<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    定義Traits?

    在Python程序中按照下面的步驟使用Traits庫:

    1. 從 enthought.traits.api 中載入你所需要的對象
    2. 定義你想使用的traits
    3. 從HasTraits類繼承一個新類,在其中使用你定義的traits聲明trait屬性

    通常第2、3步是放在一起的,也就是說定義traits的同時定義trait屬性,在本手冊中的大部分例子都是采用這種方式:

    from enthought.traits.api import HasTraits, Float
    
    class Person(HasTraits):
        weight = Float(50.0)
    

    這段程序定義了一個從HasTraits類繼承的Person類,在其內部聲明了一個名為weight的trait屬性,其類型為浮點數,初始值為50.0。trait屬性像類的屬性一樣定義,像實例的屬性一樣使用。下面我們來看看如何使用trait屬性:

    >>> joe = Person()
    >>> joe.weight
    50.0
    >>> joe.weight = 70.5
    >>> joe.weight = 70
    >>> joe.weight = "89"
    Traceback (most recent call last):
      File "...trait_handlers.py", line 175, in error value )
    TraitError: The 'weight' trait of a Person instance must be a float,
    but a value of '89' <type 'str'> was specified.
    

    由于joe是Person類的實例,因此它有一個名為weight的trait屬性,并且初始值為50.0。由于weight是使用Float聲明的,我們能將浮點數賦值給它,由于整數可以不丟失精度的轉換為浮點數,因此整數也可以賦值給它。然而,把浮點數賦值給整數trait屬性將會產生錯誤。由于字符串無法轉換為浮點數,因此賦值為字符串產生錯誤,錯誤的提示信息告訴我們它需要浮點數。

    有時候我們希望trait屬性能夠自動的進行強制類型轉換,這樣我們就可以將字符串賦值給類型為float的trait屬性,省去了手工轉換的麻煩。這種強制類型轉換的trait屬性都用Casting trait聲明,所有的Casting trait都是以 C 開頭的:

    from enthought.traits.api import HasTraits, CFloat
    
    class Person(HasTraits):
        cweight = CFloat(50.0)
    
    >>> bill = Person()
    >>> bill.cweight = "90"
    >>> bill.cweight
    90.0
    >>> bill.cweight = "abc"
    Traceback (most recent call last)
    ...
    

    這段程序用CFloat聲明了一個強制類型轉換的trait屬性cweight。我們可以將能轉換為浮點數的字符串"90"賦值給它,但是 "abc" 這樣的字符串賦值仍然會拋出異常。 我們可以想象CFloat的內部處理:它先將傳入的值用內部函數float()進行強制類型轉換,然后把結果賦值給trait屬性。

    我們也可以先單獨定義一個traits,然后用它來聲明多個類的多個trait屬性,下面是一個例子:

    from enthought.traits.api import HasTraits, Range
    
    coefficient = Range(-1.0, 1.0, 0.0)
    
    class quadratic(HasTraits):
        c2 = coefficient
        c1 = coefficient
        c0 = coefficient
        x  = Range(-100.0, 100.0, 0.0)
    

    在這個例子中,我們需要定義多個trait屬性,其類型都為Range(具有取值范圍的浮點值),并且范圍都是-1.0到1.0,初始值為0.0。為了體現代碼重用,我們先用coefficient = Range(-1.0, 1.0, 0.0)定義了一個traits,然后在quadratic類中使用它定義三個trait屬性:c0, c1, c2。

    預定義的Traits?

    Traits庫為Python的許多數據類型提供了預定義的trait類型。HasTraits派生的類中用trait類型名直接定義trait屬性,這個類的所有實例都將擁有一個初始化為缺省值的屬性,例如:

    class Person(HasTraits):
        age = Float
    

    上面的例子為Person類定義了一個age屬性,其類型為浮點數,并且被初始化為0.0(Float的缺省值)。如果你希望用別的值初始化trait屬性的話,可以把這個值當作參數傳遞給trait類型:

    age = Float(10.0)
    

    幾乎所有的trait類型都是可以帶括號調用的,它可以接受缺省值或者其它的參數;還可以通過關鍵字參數接受元數據。 .. TODO:: 插入元數據鏈接

    簡單類型?

    對于每個Python的簡單數據類型都對應兩種trait類型:強制類型和自動轉換類型。它們的區別在于:

    • 強制型Trait : 當這樣trait屬性被賦值為類型不匹配的數據時,會產生錯誤
    • 自動型Trait : 類型不匹配時會自動調用此類型對應的Pyton內置的轉換函數進行類型轉換
    強制型Trait 自動型Trait Python對應的數據類型 內置缺省值 自動轉換函數
    Bool CBool Boolean False bool()
    Complex CComplex Complex number 0+0j complex()
    Float CFloat Floating point number 0.0 float()
    Int CInt Plain integer 0 int()
    Long CLong Long integer 0L int()
    Str CStr String '' str()
    Unicode CUnicode Unicode u'' unicode()

    下面的例子演示了強制型Trait和自動型Trait之間的區別:

    >>> from enthought.traits.api import HasTraits, Float, CFloat
    >>> class Person ( HasTraits ):
    ...     weight  = Float
    ...     cweight = CFloat
    >>> bill = Person()
    >>> bill.weight  = 180    # OK, 整數和浮點數匹配(轉換為浮點數而不丟失信息)
    >>> bill.cweight = 180    # OK,
    >>> bill.weight  = '180'  # Error, 字符串和浮點數不匹配
    >>> bill.cweight = '180'  # OK, 調用float('180')轉換為浮點
    >>> print bill.cweight
    180.0
    

    其它類型?

    除了簡單類型以外,Traits庫還定義了許多其他的常用的數據類型。幾乎所有的Trait類型都可以直接使用其名稱或者當作函數調用,并且可以接受多種參數。

    • Any : 任何對象;

      Any( [value = None, **metadata] )
    • Array : numpy的數組;

      Array( [dtype = None, shape = None, value = None, typecode = None, **metadata] )
    • Button : 按鈕類型,通常用來觸發事件,參數都是用來描述界面中的按鈕的樣式;

      Button( [label ="", image = None, style = "button", orientation = "vertical", width_padding = 7, height_padding = 5, **metadata] )
    • Callable : 可調用對象;

      Callable( [value = None, **metadata] )
    • CArray : 可自動轉換類型的numpy數組; 調用的參數和Array相同

    • Class : Python老式類;

      Class( [value, **metadata] )
    • Code : 某種編程語言的字符串;

      Code( [value = "", minlen = 0, maxlen = sys.maxint, regex = "", **metadata] )
    • Color : 界面庫中所采用的顏色對象;

      Color( [*args, **metadata] )
    • CSet : 自動轉換類型的集合對象;

      CSet( [trait = None, value = None, items = True, **metadata] )
    • Constant : 常量對象,其值不能改變,必須指定初始值;

      Constant( value*[, ***metadata] )
    • Dict : 字典對象,系統還定義了一系列關鍵字為字符串的字典trait類型:DictStrAny, DictStrBool, ...;

      Dict( [key_trait = None, value_trait = None, value = None, items = True, **metadata] )
    • Directory : 表示某個目錄的路徑的字符串;

      Directory( [value ="", auto_set = False, entries = 10, exists = False, **metadata] )
    • Disallow : 表示不容許任何值,在帶有通配符的trait屬性定義中使用

    • Either : 多個trait類型的復合對象,例如 Either(Str, Float) 表示其定義的屬性類型可以是字符串或者浮點數;

      Either( val1*[, *val2, ..., valN, **metadata] )
    • Enum : 枚舉數據,其值可以是候選值中的一個;

      Enum( values*[, ***metadata] )
    • Event : 觸發事件用的對象;

      Event( [trait = None, **metadata] )
    • Expression : Python的表達式對象;

      Expression( [value ="0", **metadata] )
    • File : 表示包括路徑的文件名的字符串;

      File( [value = "", filter = None, auto_set = False, entries = 10, exists = False, **metadata ] )
    • Font : 界面庫中表示字體的對象;

      Font( [*args, **metadata] )

    This和self?

    在預定義的traits中,This和self需要單獨說明一下。它們所定義的屬性必須是包含此屬性的類(或派生類)的對象。This的缺省值為None,而self的缺省值則是包含屬性的對象本身。

    下面來看一個例子:

    class Employee(HasTraits):
        manager = self
    

    定義了一個Employee類,它有一個manager屬性,其類型為Employee,缺省值為對象本身:

    >>> e = Employee()
    >>> e.manager
    <__main__.Employee object at 0x05DB72A0>
    >>> e
    <__main__.Employee object at 0x05DB72A0>
    

    如果用This定義的話,那么缺省值為None。

    一般來說,屬性為某個類的實例時可以這樣定義:

    manager = Instance(Empolyee)
    

    但是對于這個例子中,在定義manager屬性時,Empolyee還不存在,因此無法如此定義。如果你喜歡這種方式的話,可以用Instance("Empolyee")來定義,當兩個類的屬性交叉引用時,可以使用這種字符串的方式來定義。

    This和self不但可以表示類本身,還可以表示派生的類:

    >>> from enthought.traits.api import HasTraits, This
    >>> class Employee(HasTraits):
    ...    manager = This
    ...
    >>> class Executive(Employee):
    ...  pass
    ...
    >>> fred = Employee()
    >>> mary = Executive()
    >>> fred.manager = mary
    >>> mary.manager = fred
    

    列出可能的值?

    使用Enum可以定義枚舉類型,在Enum的定義中給出所有可能的值,這些值必須是Python的簡單數據類型,例如字符串、整數、浮點數等等,各個可能的值的類型可以不一樣。可以直接將可能的值作為參數,或者將其包在某個list中,第一個值為缺省值:

    class Items(HasTraits):
        count = Enum(None, 0, 1, 2, 3, "many")
        # 或者:
        # count = Enum([None, 0, 1, 2, 3, "many"])
    

    下面是運行結果:

    >>> item = Items()
    >>> item.count = 2
    >>> item.count = "many"
    >>> item.count = 5
    

    如果你希望候選值是可以變化的話,可以用values關鍵字指定定義侯選值的屬性名:

    class Items(HasTraits):
        count_list = List([None, 0, 1, 2, 3, "many"])
        count = Enum(values="count_list")
    

    我們定義一個count_list列表,然后在Enum定義中用values關鍵字指定候選值為count_list屬性。

    >>> item = Items()
    >>> item.count = 5
    Traceback (most recent call last)
    #... 略去錯誤提示,此錯誤提示無法顯示侯選值列表
    >>> item.count_list.append(5)
    >>> item.count = 5
    >>> item.count
    5
    

    Trait的元數據?

    Trait對象可以有元數據屬性,這些屬性保存在HasTraits對象的trait字典中,為了解釋什么是trait字典和元數據,讓我們先來看一個例子:

    from enthought.traits.api import *
    
    class MetadataTest(HasTraits):
        i = Int(99)
        s = Str("test", desc="a string trait property")
    
    test = MetadataTest()
    

    在IPython中運行了上面的程序之后,我們對test進行如下操作:

    >>> test.traits()
    {'i': <enthought.traits.traits.CTrait object at 0x05D44EA0>,
    'trait_added': <enthought.traits.traits.CTrait object at 0x05D17CE8>,
    's': <enthought.traits.traits.CTrait object at 0x05D44EF8>,
    'trait_modified': <enthought.traits.traits.CTrait object at 0x05D17C90>}
    
    >>> test.trait("i")
    <enthought.traits.traits.CTrait object at 0x05D44EA0>
    
    >>> test.trait("s").desc
    'a string trait property'
    

    通過調用HasTraits對象的traits方法可以得到一個包含其所有trait對象的字典。請注意,trait屬性和trait對象是兩個東西:

    • trait屬性 : 用于保存實際的值,例如:test.i, test.s
    • trait對象 : 用于描述trait屬性,例如:test.trait("i"), test.trait("s")

    也就是說對于每一個trait屬性都有一個與之對應的trait對象描述它。而元數據就是保存在trait對象中的額外的描述屬性用的數據。我們看到test的trait對象除了i和s之外,還有trait_added和trait_modified,著兩個在HasTraits類中定義。

    元數據可以分為三類:

    • 內部屬性 : 這些屬性是trait對象自帶的,只讀不能寫
    • 識別屬性 : 這些屬性是可以自由地設置的,它們可以改變trait的一些行為
    • 任意屬性 : 用戶自己添加的屬性,需要自己編寫程序使用它們

    內部元數據?

    下面的這些元數據屬性在Traits庫內部使用,用戶可以讀取它們的值。

    • array : 是否是數組,不是數組的trait對象沒有此屬性

    • default : 對應的trait屬性的缺省值。也就是說: trait屬性的缺省值是保存在與其對應的trait對象的元數據屬性default中的:

      >>> test.trait("i").default
      99
      
    • default_kind : 一個描述缺省值的類型的字符串,其值可以是 value, list, dict, self, factory, method等:

      >>> test.trait("i").default_kind
      'value'
      
    • inner_traits : 內部的trait對象,在List, Dict等中使用,表示List和Dict內部對象的類型

    • trait_type : 描述trait屬性的數據類型的對象。下面的例子中,得到的就是定義trait屬性時所用的Int類的對象:

      >>> test.trait("i").trait_type
      <enthought.traits.trait_types.Int object at 0x05DBD2D0>
      
    • type : trait屬性的分類,可以是constant, delegate, event, property, trait

      >>> test.trait("i").type
      'trait'
      

    能識別的元數據?

    下面的元數據屬性不是預定義的,但是可以被HasTraits對象使用:

    • desc : 描述trait屬性用的字符串,在界面中使用
    • editor : 指定一個生成界面時用何種TraitEditor編輯對應的trait屬性
    • label : 界面中的trait屬性編輯器的標簽中的字符串
    • rich_compare : 指定判斷trait屬性值發生變化的方式。True(缺省)表示按值比較;Flase表示按照對象指針比較
    • trait_value : 指定trait屬性是否接受TraitValu類的對象,缺省值為False。當它為True時,將trait屬性設置為TraitValue(),將重置trait屬性值為缺省值。
    • transient : 指定當對象被保存(持久化)時是否保存此trait屬性值。對于大多數trait屬性來說,它的缺省值都是True。

    首頁目錄

    上一篇文章

    Traits使用手冊

    下一篇文章

    Trait事件處理

    97av