Python类属性或实例属性的类型限制
来源:互联网 发布:j2直播软件 编辑:程序博客网 时间:2024/06/05 16:31
0. 背景
在Python的大量类属性或是实例属性中,由于python语法的特性,属性并不带有类型,可以随意赋值,当然了也可以通过@property
用来限制某个属性,但是对于需要大量重用代码的情况下,描述符会更有用。使用描述符,与其说是类型限制,不如说是赋值时的类型检查。问题解决的目标是:
针对某个自定义的类,自定义有目标类型(比如
Integer
,String
,Float
)的类属性或是实例属性。如果在初始化或赋值操作中,需要使得属性的类型发生了转化,则会出现Error
。
1. 思路与方案
如果想创建一个具有类型限制的实例属性,可以以描述符(了解python描述符的用法)的形式定义其功能。实例如下:
# 使用描述符来对以Integer类型为属性的限制class Integer(object): def __init__(self, name): self.name = name def __get__(self, instance, cls): if instance is None: return self else: return instance.__dict__[self.name] def __set__(self, instance, value): if not isinstance(value, int): raise TypeError("Expected an int") instance.__dict__[self.name] = value def __delete__(self, instance): del instance.__dict__[self.name]
所谓的描述符就是以特殊方法__get__()
,__set__()
,__delete__()
的形式实现了三个核心的属性访问操作(对于与get
,set
和delete
)的类。这些方法通过接受类实例作为输入来工作。之后,底层的实例字典会根据需要适当地进行调整。
要使用一个描述符,我们把描述符的实例放置在类的定义中作为类变量来用。示例如下:
# 属性x,y以Integer类为类型的使用class Point(object): x = Integer('x') y = Integer('y') def __init__(self, x, y): self.x = x self.y = y
当这么做时,所有针对描述符属性(即,这里的x或y)的访问都会被__get__()
,__set__()
,__delete__()
方法所捕获
if __name__ == '__main__': p = Point(2,3) # 调用Point.__init__,进而调用 Point.x.__set__(),Point.y.__set__() print p.x # 调用Point.x.__get__() p.y = 5 # 调用Point.y.__set__() p.x = 2.3
运行的结果是:
C:\Python27>python C:\Users\snwang\Desktop\wsn_attr.py2Traceback (most recent call last): File "C:\Users\snwang\Desktop\wsn_attr.py", line 36, in <module> p.x = 2.3 File "C:\Users\snwang\Desktop\wsn_attr.py", line 17, in __set__ raise TypeError("Expected an int")TypeError: Expected an int
每个描述符方法都会接受被操纵的实例作为输入。要执行所请求的操作,底层的实例字典(即__dict__
属性)会根据需要适当的进行调整。描述符的self.name
属性会保存字典的key,通过这些key可以找到存储在实例字典中的实际数据。
2. 方案深化
上述的方案有一些不足:作为Integer
类型的已经写完了,如果我们想要写String
,或是Float
,这要我们又要重新写一遍类似的代码。遵从代码重用原则,我们应该建立一个描述符基类,然后让这些类型继承它。
下面的代码使用描述符实现了一个类型系统以及对值进行检查的框架:
# 描述符基类,用于类型检查class Typed(object): def __init__(self, name, expected_type): self.name = name self.expected_type = expected_type def __get__(self, instance, cls): if instance is None: return self else: return instance.__dict__[self.name] def __set__(self, instance, value): if not isinstance(value, self.expected_type): raise TypeError("Expected " + str(self.expected_type)) instance.__dict__[self.name] = value def __delete__(self, instance): del instance.__dict__[self.name]
创建了描述符类之后,如果属性是int类型的,那么只需设置expected_type=int,str,float
同理。
接下来我们需要写一个类装饰器,用来装饰自定义的类:在自定义类之前,将类属性设置为某特定类型的Typed
实例,代码如下:
#类装饰器,用来装饰自定义的类, 且将类属性设置为某特定类型的Typed实例def typeassert(**kwargs): def decorate(cls): for name, expected_type in kwargs.items(): # 将名字name和期望类型创建一个Typed实例 iTyped = Typed(name, expected_type) # 将名字name和iType,设置到cls中,作为对应cls.__dict__中的key,value setattr(cls, name, iTyped) return cls return decorate
然后就是使用这个类装饰器的测试代码:
# 例子使用,装饰器使用 @typeassert(name=str, shares=int, price=float) class Stock(object): def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price # 调用了 Stock.name.__set__(s, 'csdn') # Stock.shares.__set__(s, 529) # Stock.name.__set__(s, 22.08) s = Stock(name = 'csdn', shares = 529, price = 22.08) # 调用了 Stock.name.__get__(s, Stock) # Stock.shares.__get__(s, Stock) # Stock.price.__get__(s, Stock) print s.name, str(s.shares), str(s.price) # 调用了Stock.shares.__set__(s, 'this_is_a_str'),但是期望是int类型,所以会有error s.shares = 'this_is_a_str'
输出结果:
C:\Python27>python C:\Users\snwang\Desktop\typeassert.pycsdn 529 22.08Traceback (most recent call last): File "C:\Users\snwang\Desktop\typeassert.py", line 56, in <module> s.shares = 'this_is_a_str' File "C:\Users\snwang\Desktop\typeassert.py", line 18, in __set__ raise TypeError("Expected " + str(self.expected_type))TypeError: Expected <type 'int'>
最后,应该强调的是,如果只是想访问某个特定的类中的一种属性,并对此做定制化处理,那么最好不要编写描述符来实现。对于这个任务,用@property属性方法来完成会更加简单。当在需要大量重用代码的情况下,描述符会更加有用,例如,我们希望在自己的代码中大量使用描述符提供的功能,或者将其作为库来使用。
3. 总结
本文主要讲述了怎样使用描述符来对类属性进行类型限制。若想查看上面的例子全部代码,请移步我的github https://github.com/csdz/SnapToSnap/tree/master/descriptor,也欢迎关注。
- Python类属性或实例属性的类型限制
- python学习:限制实例的属性
- python的类属性和实例属性
- python的类属性和实例属性
- python 的 类属性 与 实例属性
- python的类属性和实例属性
- python的类属性和实例属性
- python的类属性和实例属性
- Python Class的实例属性/类属性
- Python类属性,实例属性
- python通过__slots__限制类实例动态的增加属性、方法
- Python 面向对象编程基础(定义类并创建实例、创建实例属性、初始化实例属性、访问限制、类属性、属性名冲突、实例方法、类方法)
- python类的类属性与实例属性
- python中类属性和实例属性的区别
- Python实例属性和类属性的区别
- 关于Python类属性与实例属性的讨论
- 关于Python类属性与实例属性的讨论
- 关于Python类属性与实例属性的讨论
- Syntax error,parameterized types are only available if source level is 5.0
- c++常见容器操作
- Hadoop 的 Oozie 工作流管理引擎的实际应用(一)
- Android 消息循环机制之ThreadLocal 类详解
- 常见的块状元素与内联元素
- Python类属性或实例属性的类型限制
- Python的100道经典算法题(1)
- zoj 2340 Little Jumper(三分 物理好题)
- Unity3d 使用 RSA和DES 加密网络数据包
- Java网络编程
- HTML——边用边学
- 【MongoDB】window环境下MongoDB64位安装
- CSS3 Transition
- 关系型数据库