关于Python的动态特性
动态解释
例1
定义三个功能类似的类:初始化名字,并有一个打印职业和名字的方法
测试文件:
写一个测试方法who_am_i
输出结果:
例2
Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:
例如,从文件读取内容并解析为JSON结果:
Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:
例如,从文件读取内容并解析为JSON结果:
import json f = open('/path/to/file.json', 'r') print json.load(f)
由于Python的动态特性,json.load()并不一定要从一个File对象读取内容。任何对象,只要有read()方法,就称为File-like Object,都可以传给json.load()。
请尝试编写一个File-like Object,把一个字符串 r'["Tim", "Bob", "Alice"]'包装成 File-like Object 并由 json.load() 解析。
import json class Students(object): def read(self): return r'["Tim", "Bob", "Alice"]' s = Students() print json.load(s) [u'Tim', u'Bob', u'Alice']
动态绑定属性
定义两个类做比较,一个定义了_slots_,另一个没有
class Player1(object): """docstring for Player1""" def __init__(self, uid, name, status = 0, level = 1): self.uid = uid self.name = name self.status = status self.level = level class Player2(object): """docstring for Player2""" __slots__ = ['uid', 'name', 'status', 'level'] def __init__(self, uid, name, status = 0, level = 1): self.uid = uid self.name = name self.status = status self.level = level
ipython做测试,导入上面的两个类,并实例化
In [4]: from SlotsTest import Player1,Player2 In [5]: p1 = Player1('001','cici') In [6]: p2 = Player2('002','coco')
先说下结论:第一个类比第二个要耗费内存
查看两个类属性的差集,看看第一个类多了什么
In [10]: set(dir(p1))-set(dir(p2)) Out[10]: {'__dict__', '__weakref__'}
!!!重点来了!!!
_dict_方法主要用于动态绑定属性,看下列测试结果
再比较一下两个对象的大小
import sys In [27]: sys.getsizeof(p1) Out[27]: 64 In [28]: sys.getsizeof(p2) Out[28]: 80 In [29]: sys.getsizeof(p1.__dict__) Out[29]: 1048
_slots_ = ['uid', 'name', 'status', 'level']
会屏蔽掉对象中的_dict_方法
屏蔽掉之后,对象将无法动态绑定属性
动态绑定函数
我们在 class 中定义的实例方法其实也是属性,它实际上是一个函数对象:
class Person(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): return 'A' p1 = Person('Bob', 90) print p1.get_grade # => <bound method Person.get_grade of <__main__.Person object at 0x109e58510>> print p1.get_grade() # => A
也就是说,p1.get_grade 返回的是一个函数对象,但这个函数是一个绑定到实例的函数,p1.get_grade() 才是方法调用。
因为方法也是一个属性,所以,它也可以动态地添加到实例上,只是需要用 types.MethodType() 把一个函数变为一个方法:
import types def fn_get_grade(self): if self.score >= 80: return 'A' if self.score >= 60: return 'B' return 'C' class Person(object): def __init__(self, name, score): self.name = name self.score = score p1 = Person('Bob', 90) p1.get_grade = types.MethodType(fn_get_grade, p1, Person) print p1.get_grade()
运行结果: A
p2 = Person('Alice', 65) print p2.get_grade()
运行结果: ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
因为p2实例并没有绑定get_grade
动态构建类
Type函数
第一个参数是类的名字,第二个元组是父类,第三个是属性。
def attr(self): ''' 定义一个函数,并绑定到对象 ''' return 1**2*3.14 T = type('TypeClass', (object,), {'a':'Hello', 'attr':attr})
print T.a print T.__dict__ print T.__name__
运行结果:Hello
dict_proxy({'a': 'Hello', '_module': '_main', 'attr': <function attr at 0x0000000004076748>, '_dict': <attribute 'dict' of 'TypeClass' objects>, '_weakref': <attribute 'weakref' of 'TypeClass' objects>, '_doc_': None})
TypeClass
t = T() print t.attr() print t.__dict__
运行结果:3.14
{}
print type(T) print type(t)
运行结果:
<type 'type'>
<class 'main.TypeClass'>