面向对象编程基础
活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”,我们先来看看比较正式的说法:把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。
类和对象
简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类”的东西。
定义类
在Python中可以使用“class”关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
class Student(object):
"""
第二步初始化,初始化自己.
当你的类有一些公用变量的时候,你就可以初始化
初始化中经常放入公有的变量.
"""
def __init__(self,name):
"""
在类中,一切的变量和函数都要印记(self)
"""
self.name = name
def student_1(self,num):
self.num = num
print(self.num)
print(self.name)
def student_2(self):
print(self.num)
print(self.name)
if __name__ == "__main__":
# 实例,类名带括号“Student()”,直接运行初始化函数
student = Student('熊大')
student.def1(99)
student.def2()
访问可见性问题
对于上面的代码,有C++、Java、C#等编程经验的程序员可能会问,我们给Student
对象绑定的`“name”“age”属性到底具有怎样的访问权限(也称为可见性)。因为在很多面向对象编程语言中,我们通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象能够接受的消息。在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头。(即:私有变量,变量名前面加"__",如果非要使用私有变量,那么可以使用dir(class())去查看它真正的名字。私有变量/函数,在类内部可以直接调用。如果你想体现一个变量/函数特别重要你可以使用"_")
但是,Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来“妨碍”对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可以验证这一点。之所以这样设定,可以用这样一句名言加以解释,就是“We are all consenting adults here”。因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。
在实际开发中,我们并不建议将属性设置为私有的,因为这会导致子类无法访问(后面会讲到)。所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻。
练习
import time
class tzx(object):
def jingdutiao(self):
for i in range(1,101):
time.sleep(0.1)
print('#'*(i),'%d %%'%i)
if __name__ == "__main__":
tzx = tzx()
tzx.jingdutiao()
#读取数据
with open('F:/Python/text.txt',mode='r') as f:
readlines = f.readlines()
print(readlines)
@property装饰器
之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效。我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下所示。
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
# 访问器 - getter方法
@property
def name(self)