Python 基础入门前四篇:html
第五篇主要介绍 Python 的面向对象基础知识,也就是类的介绍,包括类方法和属性、构造方法、方法重写、继承等,最后给出两道简单的练习题。python
先简单介绍一些名词概念。git
Python中的类提供了面向对象编程的全部基本功能:类的继承机制容许多个基类,派生类能够覆盖基类中的任何方法,方法中能够调用基类中的同名方法。github
对象能够包含任意数量和类型的数据。编程
下面是简单定义一个类:bash
# 定义一个动物类别
class Animal(object):
# 类变量
eat = True
def __init__(self, name, gender):
self.name = name
self.gender = gender
# 类方法
def run(self):
return 'Animal run!'
# 实例化类
anm = Animal('animal', 'male')
# 访问类的属性和方法
print("Animal 类的属性 eat 为:", anm.eat)
print("Animal 类的方法 run 输出为:", anm.run())
复制代码
输出结果:微信
Animal 类的属性 eat 为: True
Animal 类的方法 run 输出为: Animal run!
复制代码
上述是一个简单的类的定义,一般一个类须要有关键字 class
,而后接一个类的名字,而后若是是 python2.7
是须要如例子所示加上圆括号和 object
,但在 python3
版本中,其实能够直接以下所示:数据结构
class Animal:
复制代码
而后 __init__
是构造方法,即在进行类实例化的时候会调用该方法,也就是 anm = Animal('animal', 'male')
。python2.7
此外,对于类的方法,第一个参数也是必须带上的参数,按照惯例名称是 self
,它表明的是类的实例,也就是指向实例自己的引用,让实例自己能够访问类中的属性和方法。以下代码所示:机器学习
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
复制代码
输出结果:
<__main__.Test object at 0x000002A262E2BA20>
<class '__main__.Test'>
复制代码
能够看到 print(self)
的结果是输出当前对象的地址,而 self.__class__
表示的就是类。
刚刚说了 self
只是惯例取的名称,换成其余名称也能够,以下所示:
# 不用 self 名称
class Test2:
def prt(sss):
print(sss)
print(sss.__class__)
t2 = Test2()
t2.prt()
复制代码
输出结果是同样的,类实例的地址改变了而已。
<__main__.Test2 object at 0x000001FB7644BBA8>
<class '__main__.Test2'>
复制代码
类方法和构造方法同样,首先是关键字 def
,接着就是参数第一个必须是 self
,表示类实例的参数。
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部没法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
# 实例化类
p = people('runoob',10,30)
p.speak()
复制代码
输出结果
runoob 说: 我 10 岁。
复制代码
继承的语法定义以下:
class DerivedClassName(BaseClassName1,BaseClassName2,...):
<statement-1>
.
.
.
<statement-N>
复制代码
须要注意:
BaseClass1.method1()
),python 会从左到右搜索继承的基类是否包含该方法;下面给出一个代码例子,基类定义仍是上一节中的 people
类别,此次定义一个子类 student
# 单继承示例
class student(people):
grade = ''
def __init__(self, n, a, w, g):
# 调用父类的构造方法
people.__init__(self, n, a, w)
self.grade = g
# 覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
s = student('ken', 10, 60, 3)
s.speak()
复制代码
输出结果
ken 说: 我 10 岁了,我在读 3 年级
复制代码
这是一个单继承,即继承一个基类的示例,子类的构造方法必须先调用基类(父类)的构造方法:
# 调用父类的构造方法
people.__init__(self, n, a, w)
复制代码
另外一种调用基类的构造方法,利用 super()
函数:
super.__init__(self, n, a, w)
复制代码
上述例子还重写了基类的方法 speak()
。
方法重写是在基类的方法没法知足子类的需求时,在子类重写父类的方法。
python 也支持多继承,下面是一个例子,继续沿用刚刚定义的一个类 student
,而后再从新定义一个基类 speaker
#另外一个类,多重继承以前的准备
class speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
#多重继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test = sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中排前地父类的方法
复制代码
输出结果:
我叫 Tim,我是一个演说家,我演讲的主题是 Python
复制代码
而若是想指定任意父类的方法,能够添加下面这段代码:
# 显示调用 student 父类的 speak 方法
def speak(self):
super(student, self).speak()
复制代码
上面介绍过了, super()
函数是调用父类的一个方法,能够直接 super().method()
,但若是是多继承而且指定父类的话,就如上述所示,添加父类名字以及 self
来表示类实例。
另外,python2.7
调用 super()
方法,也须要传入父类名字和 self
两个参数。
属性和方法的访问权限,便可见性,有三种,公开、受保护以及私有,私有方法和私有属性以下定义:
类的私有属性:两个下划线开头,声明该属性私有,不能在类的外部被使用或直接访问,而在类内部的方法中使用时:self.__private_attrs
类的私有方法:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。
而若是是受保护的属性或者方法,则是一个下划线开头,例如 _protected_attr
。
下面是一个简单的示例:
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
self.__count()
def __count(self):
print('私有方法')
counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
print(counter.__secretCount) # 报错,实例不能访问私有变量
print(counter.__count())
复制代码
输出结果
1
私有方法
2
私有方法
2
复制代码
调用私有属性会报错:
AttributeError: 'JustCounter' object has no attribute '__secretCount'
复制代码
调用私有方法会报错:
AttributeError: 'JustCounter' object has no attribute '__count'
复制代码
类的属性不只能够是变量,也能够是类实例做为一个属性,例子以下所示:
class TimeCounter:
def __init__(self):
print('timer')
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def __init__(self):
self.timer = TimeCounter()
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
self.__count()
def __count(self):
print('私有方法')
counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
复制代码
一样继续采用 JustCounter
类,只是新定义 TimeCounter
,并在 JustCounter
调用构造方法,实例化一个 TimeCounter
类,输出结果:
timer
1
私有方法
2
私有方法
2
复制代码
最后是来自 Python-100-Days--Day08面向对象基础 的两道练习题:
这个例子将采用受保护的属性,即属性名字以单下划线开头,因此初始化的构造方法以下:
from time import sleep
class Clock(object):
"""数字时钟"""
def __init__(self, hour=0, minute=0, second=0):
''' 初始化三个基本属性,时,分,秒 :param hour: :param minute: :param second: '''
self._hour = hour
self._minute = minute
self._second = second
复制代码
而后是模拟时钟的运行,这里只须要注意时钟运行过程边界问题,即秒和分都是每到 60 须要置零,并让分或者时加 1,而时是每隔 24 须要进行这样的操做
def run(self):
''' 模拟时钟的运行 :return: '''
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
复制代码
最后是显示时间,须要注意时、分和秒三个属性都是整数,若是采用 %
进行格式化,须要调用 str()
方法显示将它们从整数变成字符串类型,而若是用 format()
方法,就不须要。
def show(self):
''' 显示时间 :return: '''
print("{:02d}:{:02d}:{:02d}".format(self._hour, self._minute, self._second))
复制代码
简单的运用例子,这里调用 time.sleep()
方法,每显示一次时间休眠一秒,而后运行,设置循环次数是 5 次。
# 简单时钟例子
clock = Clock(23, 59, 57)
i = 0
while i < 5:
clock.show()
sleep(1)
clock.run()
i += 1
复制代码
输出结果:
23:59:57
23:59:58
23:59:59
00:00:00
00:00:01
复制代码
第二个练习是定义一个类,描述平面上点之间的移动和距离计算
首先是基本的构造方法定义,这里做为平面上的点,须要定义的属性就是点的横纵坐标:
# 定义描述平面上点之间的移动和计算距离的类
class Point(object):
def __init__(self, x=0, y=0):
''' 初始的坐标 :param x:横坐标 :param y:纵坐标 '''
self._x = x
self._y = y
复制代码
接着,点的移动,能够有两种实现,第一种直接说明目标点的坐标:
def move_to(self, new_x, new_y):
''' 移动到新的坐标 :param new_x:新的横坐标 :param new_y:新的纵坐标 :return: '''
self._x = new_x
self._y = new_y
复制代码
第二种则是只告诉分别在横、纵两个方向移动的距离:
def move_by(self, dx, dy):
''' 移动指定的增量 :param dx:横坐标的增量 :param dy:纵坐标的增量 :return: '''
self._x += dx
self._y += dy
复制代码
而后计算点之间的距离方法,这里就须要用到刚刚从 math
库导入的方法 sqrt
,即求取平方根:
def distance(self, other):
''' 计算与另外一个点的距离 :param other: :return: '''
x_dist = self._x - other._x
y_dist = self._y - other._y
return sqrt(x_dist ** 2 + y_dist ** 2)
复制代码
最后固然就是打印当前点的坐标信息了:
def __str__(self):
''' 显示当前点坐标 :return: '''
return '({},{})'.format(self._x, self._y)
复制代码
简单的应用例子
p1 = Point(10, 20)
p2 = Point(30, 5)
print('point1:', p1)
print('point2:', p2)
p1.move_to(15, 25)
print('after move to (15, 25), point1:', p1)
p1.move_by(20, 10)
print('move by (20, 10), point1:', p1)
dist = p1.distance(p2)
print('distance between p1 and p2: ', dist)
复制代码
输出结果:
point1: (10,20)
point2: (30,5)
after move to (15, 25), point1: (15,25)
move by (20, 10), point1: (35,35)
distance between p1 and p2: 30.4138126514911
复制代码
参考:
本文简单介绍 Python 面向对象的基础内容,主要是类的定义、方法和属性介绍,继承和方法重写,这些是比较基础的内容,后续计划的进阶内容关于面向对象部分,还会继续介绍如多态、装饰器等内容。
此外,本文的代码都上传到个人 github 上了:
欢迎关注个人微信公众号--机器学习与计算机视觉,或者扫描下方的二维码,你们一块儿交流,学习和进步!