Traits----为Python添加类型定义

Python作为一种动态编程语言,它的变量没有类型,这种灵活性给快速开发带来很多便利,不过它也不是没有缺点。Traits库的一个很重要的目的就是为了解决这些缺点所带来的问题。

1.背景

Traits绘图库中有很多绘图用的对象,每个对象都有很多例如线型、颜色、字体之类的属性。为了方便用户使用,每个属性可以允许多种形式的值。例如,颜色属性可以是:

  • `red’
  • 0xff0000
  • (255, 0, 0)

也就是说可以用字符串、整数、组元等类型的值表达颜色,但是颜色属性虽然可以接受多样的值,却不是能接受所有的值,比如”abc”、0.5等等就不能很好地表示颜色。而且虽然为了方便用户使用,对外的接口可以接受各种各样形式的值,但是在内部必须有一个统一的表达方式来简化程序的实现。

用Trait属性可以很好地解决这样的问题:

  • 它可以接受能表示颜色的各种类型的值
  • 当给它赋值为不能表达颜色的值时,它能够立即捕捉到错误,并且提供一个有用的错误报告,告诉用户它能够接受什么样的值
  • 它提供一个内部的标准的颜色表达方式

看一个使用traits属性表示颜色的例子:

from enthought.traits.api import HasTraits, Color #导入HasTraits和color两个对象
class Circle(HasTraits):
    color = Color  #声明一个color属性

使用color属性:

>>> c.color
wx.Colour(255, 255, 255, 255)  #显示出缺省值
>>> c.color = "red"
>>> c.color
wx.Colour(255, 0, 0, 255)
>>> c.color = 0x00ff00
>>> c.color
wx.Colour(0, 255, 0, 255)
>>> c.color = (0, 255, 255)
>>> c.color
wx.Colour(0, 255, 255, 255)
>>> c.color = 0.5  #不支持0.5这样的浮点数,下面会出现报错信息提示所支持的值

修改颜色Trait属性的对话框:

>>> c.configure_traits()
True
>>> c.color
wx.Colour(128, 128, 128, 255)

执行c.configure_traits()之后,出现如下的对话框以供我们修改颜色属性,任意选择一个颜色、按OK按钮,看到configure_traits函数返回True,而c.color已经变为我们所选择的颜色了。
这里写图片描述

2.Traits是什么

trait为Python对象的属性增加了类型定义的功能,此外还提供了如下的额外功能:

  • 初始化:每个trait属性都定义有自己的缺省值,这个缺省值用来初始化属性
  • 验证:基于trait的属性都有明确的类型定义,只有满足定义的值才能赋值给属性
  • 委托:trait属性的值可以委托给其他对象的属性
  • 监听:trait属性的值的改变可以触发指定的函数的运行
  • 可视化:拥有trait属性的对象可以很方便地提供一个用户界面交互式地改变trait属性的值

下面这个简单的例子展示了trait所提供的这五项能力:

from enthought.traits.api import Delegate, HasTraits, Instance, Int, Str

class Parent ( HasTraits ):
    last_name = Str( 'Zhang' )  #初始化:last_name被初始化为'zhang'

class Child ( HasTraits ):
    age = Int

    # 验证: father属性的值必须是Parent类的实例
    father = Instance( Parent )
    # 委托: Child的实例的last_name属性委托给其father属性的last_name
    last_name = Delegate( 'father' )
    # 监听: 当age属性的值被修改时,下面的函数将被运行
    def _age_changed ( self, old, new ):
        print 'Age changed from %s to %s ' % ( old, new )

下面用这两个类创建立两个实例:

 p = Parent()
 c = Child()

设置father属性之后,可以得到c的last_name:

>>> c.father = p
>>> c.last_name
'Zhang'

设置c的age属性将触发_age_changed方法的执行:

>>> c.age = 4
Age changed from 0 to 4

调用configure_traits:

>>> c.configure_traits()
True

弹出一个如下的对话框,用户可以通过它修改c的trait属性,
这里写图片描述

可以看到属性按照其英文名排序,垂直排为一列。由于father属性是Parent类的实例,所以它给我们
一个按钮,点此按钮出现下面的设置father对象的tratis属性的对话框:
这里写图片描述

在上面这个对话框中修改father的Last name,child的Last name属性也随之发生变化。

3. 动态添加Trait属性

前面介绍的方法都是在类的定义中声明Trait属性,在类的实例中使用Trait属性。由于Python是动态语言,因此Traits库也提供了为某个特定的实例添加Trait属性的方法。

下面的例子,直接产生HasTraits类的一个实例a, 然后调用其add_trait方法动态地为a添加一个名为x的Trait属性,其类型为Float,初始值为3.0。

>>> from enthought.traits.api import *
>>> a = HasTraits()
>>> a.add_trait("x", Float(3.0))
>>> a.x
3.0

接下来再创建一个HasTraits类的实例b,用add_trait方法为b添加一个属性a,指定其类型为HasTraits类的实例。然后把实例a赋值给实例b的属性a:b.a。

>>> b = HasTraits()
>>> b.add_trait("a", Instance(HasTraits))
>>> b.a = a

然后为实例b添加一个类型为Delegate(代理)的属性y,它是b的属性a所表示的实例的属性x的代理,即b.y是b.a.x的代理。注意我们在用Delegate声明代理时,第一个参数b的一个属性名”a”,第二个参数是是此属性的属性名”x”,modify=True表示可以通过b.y修改b.a.x的值。我们看到当将b.y的值改为10的时候,a.x的值也同时改变了。

>>> b.add_trait("y", Delegate("a", "x", modify=True))
>>> b.y
3.0
>>> b.y = 10
>>> a.x
10.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值