深入类

1、类的构造方法
#在介绍之前,我们对前面的示例做一些改动,代码如下:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的构造方法
 4 
 5 class MyClass(object):
 6     i=123
 7     def __init__(self,name):    #注意!这里是个坑:“__init__”的“__”符号是左右两个!
 8         self.name=name
 9 
10     def f(self):
11         return  'hello,'+self.name
12 
13 use_class=MyClass('xiaoqiang')
14 print('调用类的属性:',use_class.i)
15 print('调用类的方法:',use_class.f())
#程序执行结果如下:
1 ================= RESTART: C:/Users/DL He/Desktop/类的构造方法.py =================
2 调用类的属性: 123
3 调用类的方法: hello,xiaoqiang
#若类的实例化语句写法和之前一样,即:
1 use_class=MyClass()
#程序执行结果如下:
1 ================= RESTART: C:/Users/DL He/Desktop/类的构造方法.py =================
2 Traceback (most recent call last):
3   File "C:/Users/DL He/Desktop/类的构造方法.py", line 13, in <module>
4     use_class=MyClass()
5 TypeError: __init__() missing 1 required positional argument: 'name'
#从代码和输出结果看到,实例化MyClass类时调用了__init__()方法。我们在代码中并没有指定调用__init__()方法,怎么会报__init__()方法错误呢?
#在Python中,__init__()方法是一个特殊方法,在对象实例化时会被调用。__init__()的意思时初始化,是initialization的简写。这个方法的书写方式是:先输入两个下划线,后面接着init,再接着两个下划线。这个方法也叫构造方法。在定义类时,若不显式地定义一个__init__()方法,则程序默认调用一个无参的__init__()方法。比如以下两段代码的使用效果是一样的:
#代码一:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8 -*-
 3 #__init__方法
 4 
 5 class DefaultInit(object):
 6     def __init__(self):
 7         print('类实例化时执行我,我是__init__方法。')
 8 
 9     def show(self):
10         print('我是类中定义的方法,需要通过实例化对象调用。')
11 
12 test=DefaultInit()
13 print('类实例化结束。')
14 test.show()
#程序执行结果如下:
1 ================ RESTART: C:/Users/L/Desktop/__init__()方法.py ================
2 类实例化时执行我,我是__init__方法。
3 类实例化结束。
4 我是类中定义的方法,需要通过实例化对象调用。
#代码二:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8 -*-
 3 #__init__方法_1
 4 
 5 class DefaultInit(object):
 6     def show(self):
 7         print('我是类中定义的方法,需要通过实例化对象调用。')
 8 
 9 test=DefaultInit()
10 print('类实例化结束。')
11 test.show()
#程序执行结果如下:
1 ================ RESTART: C:/Users/L/Desktop/__init__()方法.py ================
2 类实例化结束。
3 我是类中定义的方法,需要通过实例化对象调用。
#由上面的两段代码的输出结果看到,当代码中定义了__init__()方法时,实例化类时会调用该方法;若没有定义__init__()方法,实例化类时也不会报错,此时调用默认的__init__()方法。
#在Python中定义类时若没有定义构造方法(__initI__()方法),则在类的实例化时系统调用默认的构造方法。另外,__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上。
#既然__init__()方法是Python中的构造方法,那么是否可以在类中定义多个构造方法呢?我们来看下面3段代码:
#代码一:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8 -*-
 3 #__init__()方法_1
 4 
 5 class DefaultInit(object):
 6     def __init__(self):
 7         print('我是不带参数的__init__方法。')
 8 
 9 DefaultInit()
10 print('类实例化结束')
#程序执行结果如下:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 我是不带参数的__init__方法。
3 类实例化结束
#在只有一个__init__()方法时,实例化没有什么顾虑。
#代码二:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8 -*-
 3 #__init__()方法_1
 4 
 5 class DefaultInit(object):
 6     def __init__(self):
 7         print('我是不带参数的__init__方法。')
 8 
 9     def __init__(self,param):
10         print('我是带一个参数的__init__方法,参数值为:',param)
11 
12 DefaultInit('hello')
13 print('类实例化结束')
#程序执行结果如下:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 我是带一个参数的__init__方法,参数值为: hello
3 类实例化结束
#由执行结果看到,调用的是带了一个param参数的构造方法,若把类的实例化语句更改为:
1 DefaultIinit()
#执行结果为:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 Traceback (most recent call last):
3   File "__init__()方法_1.py", line 12, in <module>
4     DefaultInit()
5 TypeError: __init__() missing 1 required positional argument: 'param'
#或更改为:
1 DefaultInit('hello','world')
#执行结果为:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 Traceback (most recent call last):
3   File "__init__()方法_1.py", line 12, in <module>
4     DefaultInit('hello','world')
5 TypeError: __init__() takes 2 positional arguments but 3 were given
#由执行结果看到,实例化类时只能调用带两个占位参数的构造方法,调用其它构造方法都会报错。
#代码三:
1 class DefaultInit(object):
2     def __init__(self,param):
3         print('我是带一个参数的__init__方法,参数值为:',param)
4 
5     def __init(self):
6         print('我是不带参数的__init__方法。')
7 
8 DefaultInit()
9 print('类实例化结束')
#程序执行结果如下:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 我是不带参数的__init__方法。
3 类实例化结束
#由执行结果看到,调用的构造方法除了self外,没有其他参数。若把类的实例化语句更改为如下:
1 DefaultInit('hello')
#执行结果如下:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 Traceback (most recent call last):
3   File "__init__()方法_1.py", line 13, in <module>
4     DefaultInit('hello')
5 TypeError: __init__() takes 1 positional argument but 2 were given
#或更改为:
1 DefaultInit('hello','world')
#执行结果如下:
1 D:Pythonworkspacedatatime20171121>python __init__()方法_1.py
2 Traceback (most recent call last):
3   File "__init__()方法_1.py", line 13, in <module>
4     DefaultInit('hello','world')
5 TypeError: __init__() takes 1 positional argument but 3 were given
#由执行结果看到,实例化类时只能调用带一个占位参数的构造方法,调用其他构造方法都会报错。
#由以上几个实例我们得知,一个类中可定义多个构造方法,但实例化类时只实例化最后的构造方法,即后面的构造方法会覆盖前面的构造方法,并且需要根据最后一个构造方法的形式进行实例化。所以建议一个类中只定义一个构造函数。
 
2、类的访问权限
#在类内部有属性和方法,外部代码可以通过直接调用实例变量的方法操作数据,这样就隐藏了内部的复杂逻辑,例如:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的访问权限
 4 
 5 class Student(object):
 6     def __init__(self,name,score):
 7         self.name=name
 8         self.score=score
 9 
10     def info(self):
11         print('学生:%s;分数:%s'%(self.name,self.score))
12 
13 stu=Student('xiaoming',96)
14 print('修改前分数:',stu.score)
15 stu.info()
16 stu.score=0
17 print('修改后分数:',stu.score)
18 stu.info()
#程序执行结果如下:
1 D:Pythonworkspace>python 类的访问权限.py
2 修改前分数: 96
3 学生:xiaoming;分数:96
4 修改后分数: 0
5 学生:xiaoming;分数:0
#由代码和输出结果看到,在类中定义的非构造方法可以调用类中构造方法实例变量的属性,调用的方式为self.实例变量属性名,如代码中的self.name和self.score。可以在类的外部修改类的内部属性。如果要让内部属性不被外部访问,该如何操作?
#要让内部属性不被外部访问,可以在属性名称前加两个下划线__。在Python中,实例的变量名如果以__开头,就会变成私有变量(private),只有内部可以访问,外部不能访问。据此,我们可以把student类改一改:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的访问权限
 4 
 5 class Student(object):
 6     def __init__(self,name,score):
 7         self.__name=name
 8         self.__score=score
 9 
10     def info(self):
11         print('学生:%s;分数:%s'%(self.__name,self.__score))
12 
13 stu=Student('xiaoming',96)
14 print('修改前分数:',stu.__score)
15 stu.info()
16 stu.__score=0
17 print('修改后分数:',stu.__score)
18 stu.info()
#程序执行结果如下:
1 D:Pythonworkspace>python 类的访问权限.py
2 Traceback (most recent call last):
3   File "类的访问权限.py", line 14, in <module>
4     print('修改前分数:',stu.__score)
5 AttributeError: 'Student' object has no attribute '__score'
#由执行结果看到,我们已经无法从外部访问实例变量的属性__score了。
#这样可以确保外部代码不能随意修改对象内部的状态,通过访问限制的保护,代码更加安全。比如上面的分数对象是一个比较重要的内部对象,如果外部可以随便更改这个值,大家都随便更改自己成绩单中的分数,是比较危险的。
#如果外部代码要获取类中的name和score要如何操作呢?
#在Python中,可以为类增加get_attrs方法,获取类中的私有变量,例如上面的示例中添加get_score(name的使用方式类同)方法,代码如下:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的访问权限
 4 
 5 class Student(object):
 6     def __init__(self,name,score):
 7         self.__name=name
 8         self.__score=score
 9 
10     def info(self):
11         print('学生:%s;分数:%s'%(self.__name,self.__score))
12 
13     def get_score(self):
14         return self.__score
15 
16 stu=Student('xiaoming',96)
17 print('修改前分数:',stu.get_score())
18 stu.info()
19 print('修改后分数:',stu.get_score())
20 stu.info()
#由执行结果如下:
1 D:Pythonworkspace>python 类的访问权限.py
2 修改前分数: 96
3 学生:xiaoming;分数:96
4 修改后分数: 96
5 学生:xiaoming;分数:96
#由执行结果看到,通过get_score方法已经可以正确得到类内部的属性值。
#是否可以通过外部更改内部私有变量的值?
#在Python中,可以为类增加set_attrs方法,修改类中的私有变量,如更改上面示例中的score属性值,可以添加set_score(name使用方式类同)方法,代码如下:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的访问权限
 4 
 5 class Student(object):
 6     def __init__(self,name,score):
 7         self.__name=name
 8         self.__score=score
 9 
10     def info(self):
11         print('学生:%s;分数:%s'%(self.__name,self.__score))
12 
13     def get_score(self):
14         return self.__score
15 
16     def set_score(self,score):
17         self.__score=score
18 
19 stu=Student('xiaoming',96)
20 print('修改前分数:',stu.get_score())
21 stu.info()
22 stu.set_score(0)
23 print('修改后分数:',stu.get_score())
24 stu.info()
#程序执行结果如下:
1 D:Pythonworkspace>python 类的访问权限.py
2 修改前分数: 96
3 学生:xiaoming;分数:96
4 修改后分数: 0
5 学生:xiaoming;分数:0
#由程序执行结果看到,通过set_score方法正确更改了变量score的值。这里有个疑问,原先stu.score=0这种方式也可以修改score变量,为什么又要那么费劲定义私有变量,set.score的意义在于哪里呢?
#在Python中,通过定义私有变量和对应的set方法可以帮助我们做参数检查,避免传入无效的参数,如对上面的示例更改如下:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的访问权限
 4 
 5 class Student(object):
 6     def __init__(self,name,score):
 7         self.__name=name
 8         self.__score=score
 9 
10     def info(self):
11         print('学生:%s;分数:%s'%(self.__name,self.__score))
12 
13     def get_score(self):
14         return self.__score
15 
16     def set_score(self,score):
17         self.__score=score
18 
19     if 0<=score<=100:
20         self.__score=score
21     else:
22         print('请输入0到100的数字。')
23 
24 
25 stu=Student('xiaming',96)
26 print('修改前分数:',stu.get_score())
27 stu.info()
28 stu.set_score(-10)
29 print('修改后分数:',stu.get_score())
30 stu.info()
#程序执行结果如下:
1 修改前分数:96
2 学生:xiaoming;分数:96
3 请输入0到100的数字。
4 修改后分数:96
5 学生:xiaoming;分数:96
#由输出结果看到,调用set_score方法时,如果传入的参数不满足条件,就按照不满足条件的程序逻辑执行。
#既然类有私有变量,那么有没有私有方法呢?
#是的,类也有私有方法。类的私有方法也是以两个下划线开头,声明该方法为私有方法,且不能在类外使用。私有方法的调用方式如下:
self.__private_methods
#我们通过下面的示例,进一步了解私有方法的使用:
 1 #! /usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #类的私有方法
 4 
 5 class PrivatePublicMethod(object):
 6     def __init__(self):
 7         pass
 8 
 9     def __foo(self):           #(私有方法)
10         print('这是私有方法。')
11 
12     def foo(self):
13         print('这是公共方法。')
14         print('这是公共方法中调用私有方法。')
15         self.__foo()
16         print('公共方法调用私有方法结束。')
17 
18 pri_pub=PrivatePublicMethod()
19 print('开始调用公共方法:')
20 pri_pub.foo()
21 print('开始调用私有方法:')
22 pri_pub.__foo()
#程序执行结果如下:
 1 D:Pythonworkspace>python 类的私有方法.py
 2 开始调用公共方法:
 3 这是公共方法。
 4 这是公共方法中调用私有方法。
 5 这是私有方法。
 6 公共方法调用私有方法结束。
 7 开始调用私有方法:
 8 Traceback (most recent call last):
 9   File "类的私有方法.py", line 22, in <module>
10     pri_pub.__foo()
11 AttributeError: 'PrivatePublicMethod' object has no attribute '__foo'
#由输出结果看到,私有方法和私有变量类似,不能通过外部调用。
 
 
原文地址:https://www.cnblogs.com/DLHe/p/7919404.html