P2的实例对象
因此在打印的时候,也是将不同的实例对象传入至函数,这样就能打印出不同的实例对象的参数。
在__init__中定义的参数都属于各自的实例对象。如果我们仅想实现类的交互而不是实例的交互呢,比如我想统计这个对象有多少个实例。下面的代码是否可以呢? class cls_instance(object): inst_num=0 def __init__(self): self.inst_num+=1if __name__== "__main__": c1=cls_instance() c2=cls_instance() print c2.inst_num 通过执行结果可以看到实例个数为1.但其实有C1和C2两个实例化的对象。从下面的关系图可以看到,self.inst_num是被各自实例计数保存的。并没有做到全局共享,要做到全局共享,就必须以类的方式交互而不是实例的方式 这里就要用到classmethod这个装饰器了。代码修改如下: class cls_instance(object): inst_num=0 def __init__(self): cls_instance.inst_num+=1 @classmethod def get_no_instance(cls): return cls.inst_numif __name__== "__main__": c1=cls_instance() c2=cls_instance() print c2.get_no_instance() E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter9.py 2 首先在__init__中调用的是cls_instance.inst_num+=1。也就是通过类来对计数器进行加一,而非实例对象。然后通过get_no_instance来统计实例对象。注意,get_no_instance的参数为cls且前面带有装饰器@classmethod,因此这个cls就是代表的cls_instance这个类对象,而非实例。所以得到的实例个数就为2个 从上面的关系图很容易看出,get_no_instance中的cls参数为cls_instance类。这就是classmethod的用法。我们来看一个classmethod更实用的用法。 如果我们想实例化一个时间的类,传入具体的年,月,日 class Date_format(object): def __init__(self,day=0,month=0,year=0): self.day=day self.month=month self.year=yearif __name__== "__main__": date='2017-7-10' day,month,year=map(int,date.split('-')) d=Date_format(day,month,year) 时间的格式是2017-7-10,为了区分年,月,日,首先要按照这个格式分割开来并且转换为整数。 但是如果我们有很多类似这种格式的格式字符串信息。这样一个个的去实例也挺麻烦的。我们需要把day,month,year=map(int,date.split('-'))这个的具体实现做到类中去。通过调用类来得到一个时间实例。 class Date_format(object): def __init__(self,day=0,month=0,year=0): self.day=day self.month=month self.year=year @classmethod def from_string(cls,date_string): day,month,year=map(int,date_string.split('-')) date=cls(day,month,year) return dateif __name__== "__main__": d=Date_format.from_string('2017-7-10') print d.day,d.month,d.year 通过from_string来得到具体的日期并通过date=cls(day,month,year)来实例化对象并返回这个实例化对象 下面来看下staticmethod。还是刚才的例子,如果我们只是想得到具体的日期,而不需要实例化的话可以用到staticmethod。如下的代码: class Date_format(object): def __init__(self,day=0,month=0,year=0): self.day=day self.month=month self.year=year @classmethod def from_string(cls,date_string): day,month,year=map(int,date_string.split('-')) date=cls(day,month,year) return date @staticmethod def get_detail_time(date_string): day,month,year=map(int,date_string.split('-')) return day,month,yearif __name__== "__main__": day,month,year=Date_format.get_detail_time('2017-7-10') print day,month,year E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter9.py 2017 7 10 __slots__ class A(object): def __init__(self,x): self.x=xif __name__== "__main__": a=A(3) print a.x print a.__dict__ print a.__dict__['x'] a.y=1print a.__dict__ E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter9.py 3 {'x': 3} 3 {'y': 1, 'x': 3} 在python中,实例化对象的变量都保存在字典中,因此我们可以用a.__dict__来查看所有的属性。也可以通过a.__dict__[‘x’]来代替a.x。本质上原理都是一样的。另外也可以自由添加变量。比如a.y=1.添加成功后再字典中也能看到对应的变量。但是如果我们想固定变量,比如只有x和y该如何操作呢。这里就需要用到__slots__方法。代码修改如下: class A(object): __slots__=('x','y') def __init__(self,x,y): self.x=xif __name__== "__main__": a=A(3,2) print a.x print a.__slots__ print a.__dict__ 我们来看下运行结果: E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter9.py 3 ('x', 'y') Traceback (most recent call last): File "E:/py_prj/fluent_python/chapter9.py", line 65, in <module> print a.__dict__ AttributeError: 'A' object has no attribute '__dict__' 首先__slots__是返回的元组形式存储变量,而非字典。另外在执行__dict__的时候报错,提示没有__dict__属性。因此如果用了__slots__来设定变量,则__dict__将不会再有。那么我们可以添加变量么。我们新增一个变量z a.z=3 E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter9.py Traceback (most recent call last): File "E:/py_prj/fluent_python/chapter9.py", line 65, in <module> a.z=3 AttributeError: 'A' object has no attribute 'z' 结果提示没有z的属性。说明使用了__slots__后不能任意添加属性。 那么__slots__的优势在哪呢?不用__slots__的时候,变量是保存在字典里的。字典是很耗内存的,如果这个对象有很多个实例对象,那么每个实例对象都将会建立一个字典。在这种情况下内存的消耗是很惊人的。我们来实测一下。我们用profile来测试代码所占的内存。首先创建100000个实例对象 class A(object): def __init__(self,x,y): self.x=x self.y=y @profiledef profile_result(): f=[A(1,2) for i in range(100000)]if __name__== "__main__": profile_result() 测试结果:建立实例对象消耗了21.4M的内存 改用__slots__的方式: class A(object): __slots__=('x','y') def __init__(self,x,y): self.x=x self.y=y @profiledef profile_result(): f=[A(1,2) for i in range(100000)]if __name__== "__main__": profile_result() 测试结果:同样个数的实例值消耗了5.7M的内存。相比字典确实节省了不少的内存 最后总结一下: __slots__用元组的形式保存变量,而非字典。且__slots__无法添加变量。由于采用了元组的方式,因此在创建多个实例的时候,会节省不少内存。但由于无法添加变量,也有很大的局限性。最适合__slots__的场景就是类的变量恒定不变且会创建多个实例化对象的时候,可以采用__slots__
转载于:https://www.cnblogs.com/zhanghongfeng/p/7146195.html