返回介绍

定义 Traits

发布于 2025-02-25 22:46:22 字数 11184 浏览 0 评论 0 收藏 0

在 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自动型 TraitPython 对应的数据类型内置缺省值自动转换函数
BoolCBoolBooleanFalsebool()
ComplexCComplexComplex number0+0jcomplex()
FloatCFloatFloating point number0.0float()
IntCIntPlain integer0int()
LongCLongLong integer0Lint()
StrCStrString''str()
UnicodeCUnicodeUnicodeu''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 : 任何对象;
    Array( [dtype = None, shape = None, value = None, typecode = None, **metadata] )
    
  • Button : 按钮类型,通常用来触发事件,参数都是用来描述界面中的按钮的样式;
    Callable( [value = None, **metadata] )
    
    • CArray : 可自动转换类型的 numpy 数组; 调用的参数和 Array 相同
    • Class : Python 老式类;
    Code( [value = "", minlen = 0, maxlen = sys.maxint, regex = "", **metadata] )
    
    • Color : 界面库中所采用的颜色对象;
    CSet( [trait = None, value = None, items = True, **metadata] )
    
    • Constant : 常量对象,其值不能改变,必须指定初始值;
    Dict( [key_trait = None, value_trait = None, value = None, items = True, **metadata] )
    
    • Directory : 表示某个目录的路径的字符串;
    Either( val1*[, *val2, ..., valN, **metadata] )
    
    • Enum : 枚举数据,其值可以是候选值中的一个;
    Event( [trait = None, **metadata] )
    
    • Expression : Python 的表达式对象;
    File( [value = "", filter = None, auto_set = False, entries = 10, exists = False, **metadata ] )
    
    • Font : 界面库中表示字体的对象;
    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。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文