回顾
回顾:字符串、列表、字典的修改关于内存的情况
一、字符串
str1 = 'luotianshuai' str2 = str1 print id(str1) print id(str2) print '===========================' str1 = 'shuaige' print id(str1) print id(str2) #输出结果: ''' 38807904 38807904 =========================== 39795488 38807904 '''
看下我上面的例子,我给str1设置了一个值,并且让str2等于str1。现在他们的值是相等的。
然后我给str1又赋予了一个新的值'shuaige'但是为什么str2的值没有改变呢?
在看下面的例子:
str1 = str('luotianshuai') str2 = str(str1) print str1 print str2 print id(str1) print id(str2) ''' 输出结果: luotianshuai luotianshuai 41953632 41953632 '''
和上面的例子有什么不同,学完python的面向对象之后,知道python一切实物都是对象,那么咱们在创建字符串的时候是否是创建一个对象呢?是的!
咱们都知道每个对象都是独立的并且存储在内存中的某一块内存空间!
现在在看上面的例子:
我实例化str1的时候生成了一个对象,然后在生成str2的时候有生成了一个对象,然后str2里传的参数是str1。这样str2的内存地址是不是指向了str1
那么如果现在在去想str1 = '新值' 是不是重新实例化,那么他的内存地址是肯定变更了,但是str2会跟着变更吗?咱们知道str1重新实例化的时候并不是在原有的内存块里修改
而是新开辟一块空间!但是他并没有影响str2,str指向的内存地址还是原来的!
二、列表(字典的原理也是相同的)
OK 上面的例子看完了,咱们现在在看列表的例子
list1 = list([11,22,33,44]) list2 = list1 print id(list1) print id(list1) print '--------------------' list1.append(55) print id(list1) print id(list2) ''' 输出结果: 40970440 40970440 -------------------- 40970440 40970440 '''
结合上面的例子,咱们看下为什么list1的值改变后,list2也跟着改变呢?
仔细看的同学能看出来,我这个操作其实并没有给list1重新定义(没有重新实例化,仅仅修改了里面的值)
那么list1和list2的指向也是同一个内存(这个内存里包含了里面元素的内存地址,可以这么理解),对象所指的内存没变,而是对象里面的普通字段变更了!
看下下面的我自己写的类:
#!/usr/bin/env python #-*- coding:utf-8 -*- class Foo(object): def __init__(self,string): self.string = string def appendstring(self): self.string = self.string + ' is so shuai' mlist = Foo('tianshuai') mlist2 = mlist print mlist.string print mlist2.string print '--------------------------' print id(mlist) print id(mlist2) print '--------------------------' mlist.appendstring() print mlist.string print mlist2.string print '##########################' print id(mlist) print id(mlist2) ''' 输出结果: tianshuai tianshuai -------------------------- 40110848 40110848 -------------------------- tianshuai is so shuai tianshuai is so shuai ########################## 40110848 40110848 '''
哦也~~ 从这里就应该能看出来了!咱们在操作列表里的元素的时候就相当于操作对象里的普通字段,对象的存在没有被变更变更的仅是对象里存在的字段!
那好现在我在给mlist 重新定义下,现在看下mlist 和mlist2是否相等呢?,看下现在的结果:
#!/usr/bin/env python #-*- coding:utf-8 -*- class Foo(object): def __init__(self,string): self.string = string def appendstring(self): self.string = self.string + ' is so shuai' mlist = Foo('tianshuai') mlist2 = mlist print mlist.string print mlist2.string print '--------------------------' print id(mlist) print id(mlist2) print '--------------------------' mlist.appendstring() print mlist.string print mlist2.string print '##########################' print id(mlist) print id(mlist2) ''' 输出结果: tianshuai tianshuai -------------------------- 40110848 40110848 -------------------------- tianshuai is so shuai tianshuai is so shuai ########################## 40110848 40110848 ''' mlist = Foo('new name Tim') print mlist.string print mlist2.string print '------------------' print id(mlist) print id(mlist2) ''' 输出结果: tianshuai tianshuai -------------------------- 36310656 36310656 -------------------------- tianshuai is so shuai tianshuai is so shuai ########################## 36310656 36310656 new name Tim tianshuai is so shuai ------------------ 39812232 36310656 '''
OK 了解顺了一遍想当NICE
类的静态字段
关于字符串、列表、字典的回顾和静态字段关系不是很大!只是回顾看下!
一、场景一
首先回顾一下静态字段、普通字段!
class Father(object): money = 1000 #静态字段 def __init__(self, name): # 普通字段 self.name = name # 直接访问普通字段 obj = Father('laowang') print obj.name # 直接访问静态字段 print Father.money #普通字段是通过对象来访问的 #静态字段是通过类来访问的
有个这样的需求,老王和小王他们要公用一张银行卡!咱们之前也说过,静态字段是由类来调用的,普通字段是由对象来调用的,咱们看下,当前类成员和对象成员
print obj.__dict__ print Father.__dict__.keys() ''' laowang 1000 ------------------------------ {'name': 'laowang'} ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] '''
那你说现在我要用对象去调用这个静态字段是否可以调用呢?是可以的但是有个问题就是,他能调用静态字段,但是他把静态字段当作一个副本存储在对象中了,当对象在修改的时候,并不是修改
的类的静态字段,而是类似修改普通字段!
这也是老师经常说的:静态字段和普通字段的区别是,静态字段是由类调用的普通字段是由对象来调用的!平时操作的时候要注意,不要用对象去操作静态字段
既然普通字段里没有为什么他能找到静态字段呢?
还级的类对象指针吗?他就是通过类对象指针去找的!
#!/usr/bin/env python #-*- coding:utf-8 -*- class Father(object): money = 1000 #静态字段 def __init__(self, name): # 普通字段 self.name = name # 直接访问普通字段 obj = Father('laowang') obj2 = Father('xiaowang') print obj.name print obj2.name # 直接访问静态字段 print Father.money #普通字段是通过对象来访问的 #静态字段是通过类来访问的 print '------------------------------' print obj.__dict__ print obj2.__dict__ print Father.__dict__.keys() ''' laowang xiaowang 1000 ------------------------------ {'name': 'laowang'} {'name': 'xiaowang'} ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] '''
在这里看下,我现在使用对象来调用静态字段看看!
#!/usr/bin/env python #-*- coding:utf-8 -*- class Father(object): money = 1000 #静态字段 def __init__(self, name): # 普通字段 self.name = name # 直接访问普通字段 obj = Father('laowang') obj2 = Father('xiaowang') print obj.name print obj2.name # 直接访问静态字段 print Father.money #普通字段是通过对象来访问的 #静态字段是通过类来访问的 print '------------------------------' print obj.__dict__ print obj2.__dict__ print Father.__dict__.keys() ''' laowang xiaowang 1000 ------------------------------ {'name': 'laowang'} {'name': 'xiaowang'} ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] ''' #Father.money = Father.money + 1000000 obj.money = obj.money + 101 obj2.money = obj2.money + 102 print obj.money print obj2.money print obj.__dict__ print obj2.__dict__ print Father.__dict__.keys() ''' 输出结果: laowang xiaowang 1000 ------------------------------ {'name': 'laowang'} {'name': 'xiaowang'} ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] 1101 1102 {'money': 1101, 'name': 'laowang'} {'money': 1102, 'name': 'xiaowang'} ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] '''
从输出结果中就能看出来!当对象在去修改这个字段的时候,他首先会在自己那里找下(普通字段是存在对象中的),如果没有他就会通过类对象指针去查找字段发现类中有一个“静态字段”,这个静态字段的名称和咱们在对象输入的名称相同
他会把复制一下这个静态字段的信息保存到对象中,那么现在保存在对象中的这个”静态字段“还是静态字段吗?还是一个普通字段?
说了这么多的作用是什么:
在调用静态字段的时候不要用对象去调用。除非你想把静态字段在对象中使用并且当作普通字段来使用!如果你想要修该静态字段,应该使用类来调用!
并且注意下,我还测试了一个,如果一个类中,有普通字段和静态字段(两个是同名的)你对象在调用这个字段的时候调用的肯定是自己的普通字段,当然也有办法调用静态字段!
class Father(object): money = 1000 def __init__(self,name,money): self.name = name self.money = money father_obj1 = Father('shuai',100) #实例化一个对象 print Father.__dict__.keys() #类中的成员 print father_obj1.__dict__ #对象中的成员 print Father.money #调用静态字段 print father_obj1.money #这么调用只能调用普通字段 print father_obj1.__class__.money #这个可以用这个方法让对象调用静态字段 ''' 输出结果: ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] {'money': 100, 'name': 'shuai'} 1000 100 1000 '''
二、场景二
考虑一个问题,同样是这个类,我现在要写两个派生类!你说能从派生类里,去修改基类的静态字段吗?
看下下面的例子:(关于对象修改静态字段我就不在重复了)
#!/usr/bin/env python #-*- coding:utf-8 -*- class Father(object): money = 1000 #静态字段 def __init__(self, name): # 普通字段 self.name = name class Child(Father): pass class Child2(Father): pass print Father.__dict__.keys() print Child.__dict__ print Child2.__dict__ ''' ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] {'__module__': '__main__', '__doc__': None} {'__module__': '__main__', '__doc__': None} '''
我先打印一下,当前基类中和派生类中的成员,可以看出,如果派生类不调用或实例化的话是不会向父类那里获取相关方法或参数的!
好看下,我现在在派生类中,用派生类去修改静态方法!然后打印一下,现在派生类中的成员,基类的静态字段会改变吗?
#!/usr/bin/env python #-*- coding:utf-8 -*- class Father(object): money = 1000 #静态字段 def __init__(self, name): # 普通字段 self.name = name class Child(Father): pass class Child2(Father): pass print Father.__dict__.keys() print Child.__dict__ print Child2.__dict__ ''' ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] {'__module__': '__main__', '__doc__': None} {'__module__': '__main__', '__doc__': None} ''' Child.money = Child.money + 100 Child2.money = Child2.money + 102 print Father.money print Child.money print Child2.money print Father.__dict__.keys() print Child.__dict__.keys() print Child2.__dict__.keys() ''' 输出结果: ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] {'__module__': '__main__', '__doc__': None} {'__module__': '__main__', '__doc__': None} 1000 1100 1102 ['__module__', 'money', '__dict__', '__weakref__', '__doc__', '__init__'] ['money', '__module__', '__doc__'] ['money', '__module__', '__doc__'] '''
从结果可以看出,你在修改派生类中的静态字段的时候,其实也是相当于在基类中复制了一个副本。下次在调用派生类的时候直接在自己的类中调就可以了不会在去基类中查找!
说这个的目的是什么:
如果你想在派生类中想修改基类的静态方法的时候,不要调用派生类中的静态字段,需要调用基类的静态字段!