关于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'>

 

posted @ 2020-09-22 19:57  Edward_han  阅读(300)  评论(0编辑  收藏  举报