我们这里就直奔主题,不做基础铺垫,默认你有一些Python类的基础,大家在看这篇博客的时候,如果基础知识忘了,可以去菜鸟教程
从一个简单的类开始
class A(): #定义一个类 A
a = 100 #公有变量
_b = 200 #公有变量
__c = 300 #私有变量
__d__ = 400 #公有变量
a = A() #实例化一个对象a,当然可以取另外一个名字b
print(a.a,a._b,a.__c,a.__d__) #打印四个变量的值
运行结果:
Traceback (most recent call last):
File “c:\users\12090\desktop\a.py”, line 7, in
print(a.a,a._b,a.__c,a.d)
AttributeError: ‘A’ object has no attribute ‘__c’
运行结果,提示__c不能访问,这里的错误信息,并没有指出__c是私有变量,在类外不能访问
我们程序这样改动
通过成员函数间接访问私有变量
a=A,和a=A()的区别
我们把第8行改造一下:
去掉括号,就像这样:
a = A会成功生成对象a,而且通过对象a可以正确访问到公有变量a,_b,d。但是在调用函数print_c()的时候,出问题,错误提示
TypeError: print_c() missing 1 required positional argument: ‘self’
提示缺少参数,怎么解决这个问题呢:
显示传递一个类,或者对象进去
那么a=A,和a=A()有什么区别呢?
区别是:
如果是a=A,则不会调用类中的构造函数;
如果是a=A(),则会调用构造函数;
A()会调用构造函数
我们来做一个实验,
python中的构造函数名是系统规定的,init,添加后如下:
class A(): #定义一个类 A
a = 100 #公有变量
_b = 200 #公有变量
__c = 300 #私有变量
__d__ = 400 #公有变量
def __init__(self): #构造函数定义
print('calling __init__....')
def print_c(self): #通过成员函数访问私有变量
return self.__c
a = A #不会调用构造函数
print(a.a,a._b,a.print_c(a),a.__d__)
b = A() #会调用构造函数
print(b.a,b._b,b.print_c(),b.__d__)
运行结果:
当我们通过A()这种形式构造对象的时候,会显示调用构造函数__init__。
当我们通过A这种形式构造对象的时候,不会调用构造函数。
构造函数,构造了什么
“构造”这个词,是一个动词,就是要造一个东西,那么造什么呢,其实我们上面的例子,可能让初学者有点不明所以,所以接下来,我们让构造函数做点有意义的事情,程序如下:
class A(): #定义一个类 A
a = 100 #公有变量
_b = 200 #公有变量
__c = 300 #私有变量
__d__ = 400 #公有变量
def __init__(self,a,b,c,d): #通过构造函数给公有变量或者私有变量重新赋值
print('构造前:',self.a,self._b,self.__c,self.__d__)
self.a = a
self._b = b
self.__c = c
self.__d__ = d
print('构造后:',self.a,self._b,self.__c,self.__d__)
def print_c(self): #通过成员函数访问私有变量
return self.__c
a = A(1000,2000,3000,4000) #通过传值构造对象
运行结果:
这个例子,就证明了构造函数的作用
python中 self的作用
self这个单词是自己,自我的意思,它代表对象本身,其实你可以换一个单词也可以,比如you
照样可以运行
甚至一个地方用self,一个地方用you也可以
self的实际意义
我们一般使用self,python系统也默认是self,但是self的作用远不止单词意思这么简单
比如我们去掉self
运行起来,好像也没问题,但是这里的a,_b,__c,d(构造函数里面),并不是公有变量中的a,_b,__c,d。怎么见得呢?
我们把第七行打开
运行结果出错:
Traceback (most recent call last):
File “c:\users\12090\desktop\a.py”, line 13, in
a = A(1000,2000,3000,4000) #调用构造函数
File “c:\users\12090\desktop\a.py”, line 7, in init
print(‘构造前:’,a,_b,__c,d)
UnboundLocalError: local variable ‘_b’ referenced before assignment
错误原因,是本地变量_b没有引用,这个local是本地的意思,也就是在构造函数__init__函数作用范围内。那么第7行的a为什么没有报错呢,因为a用的是参数里面的a,并不是公有变量中a。
所以,第12行的打印结果,其实打印的是局部变量,也就是说,在构造函数里面我们定义了一套与公有变量同名的变量,在这种情况下,局部变量优先。
所以,self其实非常有作用,必须通过self来显示指定公有变量,不然会当作局部变量。
我们还可以进一步说明这个问题
进一步证明
结论
Python类中公有变量和私有变量定义一般定义在类名下面,构造函数上面,比如这样:
class A:
公有变量
私有变量
def init():
。。。
其中私有变量需要有前缀下划线__
如果成员函数(包括构造函数),中出现了与公有变量(私有变量)同名的变量,则python系统会屏蔽公有变量和私有变量,把改变量当成局部变量。如果要在成员函数(包括构造函数)使用公有变量和私有变量,必须通过self显示指定,就像这样:
class A:
a = 100
_b = 200
__c = 300
def init(self,a,b,c):
self.a = a #使用公有变量a
_b = b #屏蔽了公有变量_b,重新定义了一个局部变量_b
self.__c =c #使用私有变量__c