实现一些类,并希望能像静态类型语言(C,C++,Java)能对它们的实例属性做类型检查
p = Person()
p.name = 'Bob' # 必须是str
p.age = 18 # 必须是int
p.height = 1.83 # 必须是float
要求:
1.可以对实例变量名指定类型
2.赋予不正确类型时抛出异常
#
使用描述符来实现需要类型检查的属性:
分别实现__get__,__set__,__delete__方法,在__set__内使用isinstance函数做类型检查
# 描述符:包含上面3个方法其中一个的类
class Descriptor(object):
def __get__(self, instance, cls):
print 'in __get__', instance, cls
# return instance.__dict__[xxx]
def __set__(self, instance, value):
print 'in __set__'
# instance.__dict__[xxx] = value
def __delete__(self, instance):
print 'in __del__'
# del instance.__dict__[xxx]
class A(object):
x = Descriptor()
a = A() # a对x的读写删除操作,将会被描述符截获
a.x # 实例没有a.x,内容有x并且是个描述符;访问x是由a进行的,a传入到__get__的instance中,cls是a的类就是A
A.x # 类直接访问类属性,instance会传入None;可以区分是由实例访问x还是类访问x
a.x = 5
del a.x
a.x
print a.__dict__ # {} ;说明x不是a的属性
# 在描述符中,访问的是instance.__dict__这个字典,对于instance真正属性进行操作
class Descriptor(object):
def __get__(self, instance, cls):
print 'in __get__', instance, cls
return instance.__dict__['x']
def __set__(self, instance, value):
print 'in __set__'
instance.__dict__['x'] = value # 变成实例a的属性;'x'是随意的,可以通过添加描述符的构造器来定义
def __delete__(self, instance):
print 'in __del__'
# del instance.__dict__[xxx]
class A(object):
x = Descriptor()
a.x = 5
print a.x # 5
可以在__set__中进行检查的操作:
class Attr(object):
def __init__(self,name,type_): # 内置类型名
self.name = name
self.type_ = type_
def __get__(self, instance, cls):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.type_):
raise TypeError('expected an %s' % self.type_)
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
class Person(object):
name = Attr('name', str)
age = Attr('age', int)
height = Attr('height', float)
p = Person()
p.name = 'Bob'
print p.name
p.age = '17' # 抛出异常
环状数据结构中管理内存
class A(object):
def __del__(self):
print 'in A.__del__'
a = A()
import sys
sys.getrefcount(a) # 2 ; 查看一个对象的引用计数,会比想象的多1个:函数调用,a会传给函数的参数,此时便有2个变量名引用A()这个对象
a2 = a
sys.getrefcount(a) # 3
当引用计数为1的时候,A()这个对象被回收
del a2
sys.getrefcount(a) # 2
a = 5 # in A.__del__ ; 引用数字5,不在引用A(),析构函数被调用,说明A()已经被释放掉了
Python析构函数是Python语言中一种特殊的成员函数,它定义在类中,会自动调用,当对象被销毁时,析构函数会被调用。析构函数可以用来做一些清理工作,比如释放所有占用的系统资源,关闭文件,等等。 析构函数在Python中的定义格式为: def __del__(self): # 析构函数的定义 析构函数是一个类的特殊方法,它不能传递参数,因此可以使用' self' 来引用类中创建的对象,从而获取对象的相关数据。
python中,垃圾回收器通过引用计数来回收垃圾对象,某些环状数据结构(树,图...)存在对象间的循环引用,比如树的父节点引用子节点,子节点也同时引用父节点,此时同时del掉引用父子节点,两个对象不能被立即回收。
class Data(object):
def __init__(self, value, owner):
self.owner = owner
self.value = value
def __str__(self):
return '%s is data, value is %s' % (self.owner, self.value)
def __del__(self):
print 'in Data.__del__'
class Node(object):
def __init__(self, value):
self.data = Data(value, self) # Node自身对象传入Data中的owner,此时形成一个循环引用;self.data引用Data,self.owner引用Node
def __del__(self):
print 'in Node.__del__'
node = Node(100)
del node
raw_input('wait...') # 无其他输出,析构函数未触发,没有立即释放
import gc
gc.collect() #
raw_input('wait...') # 因为定义了每个类的析构函数,gc也无法强制回收
#
使用标准库weakref(弱引用),它可以创建一种能访问对象但不增加引用计数
a = A()
sys.getrefcount(a) -1 # 1
import weakref
a_wref = weakref.ref(a)
a2 = a_wref()
a is a2 # True
sys.getrefcount(a) -1 # 2
del a
del a2 # in A.__del__ # 对象的析构函数被调用,垃圾回收
a_wref()
a_wref() is None # True; 实际上是返回了一个None
import weakref
class Data(object):
def __init__(self, value, owner):
self.owner = weakref.ref(owner)
self.value = value
def __str__(self):
return '%s is data, value is %s' % (self.owner(), self.value) # 使用owner弱引用时,是一种调用形式
def __del__(self):
print 'in Data.__del__'
class Node(object):
def __init__(self, value):
self.data = Data(value, self)
def __del__(self):
print 'in Node.__del__'
node = Node(100)
del node
# in Node.__del__
# in Data.__del__ 都被回收掉
raw_input('wait...')