python _单下划线与__双下划线变量引用
python2.7,突然对_和__开头的变量产生了兴趣,这里记录一下。并不包含__xx__的变量
_和__的区别
以_与__开头的变量是特殊的变量,简单的说:
模块内:
_单下划线的变量可以被实例使用(即实例名._变量),也可以被类使用(即可通过类名._变量使用),继承后可以被重写
__双下划线的变量不可被实例使用(实例名.__变量报错),在类内部可以被类使用,在类外部不能被类使用,继承后重写无效,可以理解为不能被继承
模块外:
使用命名空间的引用(即import 模块 或者 from xx import 模块),通过模块._变量访问,同模块内规则
使用*的引用(from xx import * ),除非__all__中指明,否则带下划线的变量都不能使用
例子
class A:
_arg=0 #_单下划线变量
__arg=0; #__双下划线变量
def _fn(self): #_单下划线方法
return '_fn'
def __fn(self): #__双下划线方法
return '__fn'
def p_fn(self):
return self._fn() #类内部,使用_单下划线方法
def p__fn(self):
return self.__fn(); #类内部,使用__双下划线方法
def getArg(self):
return self.__arg; #在类内部,__双下划线变量可以使用 self. 使用,实例本身没有定义同名变量的情况下,会引用类的该同名变量
def getArg2(self):
return A.__arg; #在类内部,__双下划线变量可以使用 类名. 使用
#以下为实例自身的__双下划线变量赋值和取值,类似于java中的private变量了
def getpri(self):
return self.__pri;
def setpri(self,val):
self.__pri=val
class B(A):
'''继承A类'''
def _fn(self):
'''可以重写_单下划线方法'''
return 'B_fn'
def __fn(self):
'''不可重写__双下划线,这样写不会报错,但继承来的A中的方法调用的还是A中的__fn,重写的__fn只在B类下才可调用'''
return 'B__fn'
def get__fn(self):
'''调用子类B自身的__双下划线变量,并且,子类不能直接使用self.来调用父类A中的__双下划线变量!!'''
return self.__fn()
a=A()
print a.p_fn(),'实例调用,可在类的其他方法内调用_单下划线变量'#输出 _fn
print a.p__fn(),'实例调用,可在类的其他方法内调用__双下划线变量'#输出 __fn
print a._fn(),a._arg,'实例调用,可直接调用__单下划线变量,使用pycharm时并未给出该方法和变量的联想,但可以使用'#输出 _fn 0
# print a.__fn(),'实例调用,报错'
# print a.__arg,'实例调用,报错'
print A._arg,'类调用,可以使用_单下划线变量pycharm也没有给出联想'#输出 0
# print A.__arg,'类调用,报错'
print A._fn(a),'类调用,可以使用_单下划线变量pycharm也没有给出联想'#输出 _fn
b=B()
print b.p_fn(),'实例调用,可以看见输出的内容被重写'#输出 B_fn
print b.p__fn(),'实例调用,可以看见输出的内容未被重写,实际上是继承自A类的方法调用了A类的__fn方法'#输出 __fn #如果被重写,应该输出 B__fn
print b.get__fn(),'输出自己__fn方法'#输出B_fn
a.setpri(3)
print a.getpri() #输出3
print a.__pri #报错,该变量确实为private变量
c=A()
c.setpri(9)
print c.getpri() #输出9,优先使用实例的同名变量,
hasattr()函数在类及实例中无法判断__双下滑线变量是否存在
在写单例模式练手的时候发现,对于__双下划线的变量虽然能够对外隐藏,但对内使用hasattr函数总返回不存在,debug发现__双下滑线在实例中以 _类名__变量名 (A类的__d变量则存为 _A__d)的形式存在;
class A:
__d=00
def set(self):
self.__arg={1:1}
def get(self):
return hasattr(self,'_A__arg')
a=A()
print hasattr(a,'__d'),'直接判断__d是否存在' #输出False,判断失败
print hasattr(a,'_A__d'),'判断_A__d是否存在' #输出True
print a.get(),'赋值前' #输出False
a.set()
print a.get(),'赋值后' #输出True
b=A()
print b.get(),'__双下划线私有变量也是可以跟实例,此处新的实例未赋值,仍旧为False'