面向对象编程基础
在Python中可以使用class
关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
class Student(object):
# __init__是一个特殊方法用于在创建对象时进行初始化操作
# 通过这个方法我们可以为学生对象绑定name和age两个属性
def __init__(self, name, age):
self.name = name
self.age = age
def study(self, course_name):
print('%s正在学习%s.' % (self.name, course_name))
# PEP 8要求标识符的名字用全小写多个单词用下划线连接
# 但是很多程序员和公司更倾向于使用驼峰命名法(驼峰标识)
def watch_av(self):
if self.age < 18:
print('%s只能观看《熊出没》.' % self.name)
else:
print('%s正在观看岛国爱情动作片.' % self.name)
创建和使用对象
当我们定义好一个类之后,可以通过下面的方式来创建对象并给对象发消息
stu = Student('aaron', 18)
stu.study('math')
stu.watch_av()
访问可见性问题
对于上面的代码,有C++、Java、C#等编程经验的程序员可能会问,我们给Student
对象绑定的name
和age
属性到底具有怎样的访问权限(也称为可见性)。因为在很多面向对象编程语言中,我们通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象能够接受的消息。在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头,下面的代码可以验证这一点。
class Student:
def __init__(self, foo):
self.__foo = foo
def __bar(self):
print(self.__foo)
print('__bar')
def main():
test = Student('hello')
test._Student__bar()
print(test._Student__foo)
if __name__ == "__main__":
main()
在实际开发中,我们并不建议将属性设置为私有的,因为这会导致子类无法访问(后面会讲到)。所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻,关于这一点可以看看我的《Python - 那些年我们踩过的那些坑》文章中的讲解
面向对象的支柱
面向对象有三大支柱:封装、继承和多态。后面两个概念在下一个章节中进行详细的说明,这里我们先说一下什么是封装。我自己对封装的理解是“隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口”。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
练习
练习1 定义一个类描述数字时钟
'''
@Description:
@Version: 1.0
@Autor: AaronLuo
@Date: 2020-03-19 14:23:34
@LastEditors: AaronLuo
@LastEditTime: 2020-03-19 15:12:11
'''
from time import sleep
class Clock(object):
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour
self.minute = minute
self.second = second
def showTime(self):
print('%02d:%02d:%02d' % (self.hour, self.minute, self.second))
# print(self.hour, ':', self.minute, ':', self.second)
def caculate(self):
self.second += 1
if self.second == 60:
self.minute += 1
self.second = 0
if self.second == 60:
self.hour += 1
self.minute = 0
if self.hour == 24:
self.hour = 0
time = Clock(15, 6, 34)
while True:
time.caculate()
sleep(1)
time.showTime()
练习2:定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法。
'''
@Description:
@Version: 1.0
@Autor: AaronLuo
@Date: 2020-03-19 14:23:34
@LastEditors: AaronLuo
@LastEditTime: 2020-03-19 15:31:45
'''
from math import sqrt
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def moveTo(self, x, y):
self.x = x
self.y = y
def moveBy(self, dx, dy):
self.x += dx
self.y += dy
def distanceTo(self, this):
return sqrt((self.x - this.x)**2 + (self.y - this.y) ** 2)
def __str__(self):
return '(%s,%s)' % (str(self.x), str(self.y))
p1 = Point(3, 4)
p2 = Point()
print(p1)
print(p1.distanceTo(p2))