滚雪球学Python第四轮|10. python入门速通教程之类、继承类、类中的特殊方法
python 学习过程中,对新手来说,最难的就是面向对象部分了,但又不得不把它掌握。
在 python 中所有的内容都是对象python 中的类 学习面向对象,第一个知识点就是类,它可以看成是对象的设计图,通过提炼各种相似对象的属性和方法,然后形成一个“模板”,就是类。
在正式开始前,一定要明确一个类可以实例化出多个对象实例,这句话中也包含了,对象、实例、类之间的关系,一定要理解清楚。
类是在程序中实例化对象的设计图
类的定义
使用关键字
class
定义类,class
后面为类名,类名一般采用驼峰命名法,即 MyClass
,单词首字母大写。class MyClass:
passc = MyClass()
c.name = "橡皮擦"
print(c.name)
类的调用与函数类似,使用
类名()
即可,上述 MyClass
是一个空白类(设计图),调用类之后赋值给变量 c
,此时的 c
就是类的一个实例对象,一般简称为实例或对象。使用点号
.
,可以给对象添加属性,每个对象都可以添加自己的属性。当然一个类可以实例化出多个对象
class MyClass:
passc1 = MyClass()
c1.name = "橡皮擦"
print(c1.name)c2 = MyClass()
c2.name = "大象"
print(c1.name)
print(c2.name)
**类的初始化方法
__init__
**在类中可以直接定义类初始化时的方法
__init__
,该方法在实例生成时执行,类中的方法与普通的函数存在一个小的差异,就是类中的方法必须带有关键字 self
,即实例本身,该关键字可以为任意变量名,只是约定俗成为 self
。声明一个类,并给类增加一个初始化方法。
# 定义类
class MyClass:
# 初始化方法,第一个参数为对象本身 self,第二个参数为实例化时必须传递的参数
def __init__(self, name):
print(name)# 类的调用,只需要传递 name 参数即可
c = MyClass("橡皮擦")
在初始化方法中,可以直接给
self
绑定属性,例如下述代码:class MyClass:
def __init__(self, name):
# 将传递进来的 name 参数绑定到对象(self)上
self.name = namec = MyClass("橡皮擦")
print(c.name)
类的定义是一个抽象概念的过程
下面将通过一个简单类定义的过程,为你展示类的抽象过程。
我们要定义一个学生类,这个类是一个设计图,用它可以实例化出多个学生对象。
首先定义一个空类:
class Student:
pass
接下来要思考的是,在类调用(实例化)初始化时就传递学生姓名与性别,可以大幅度提高类的便捷性。
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sex
学生类具备属性之后,一个学生还应该具备跑这一动作,动作就是方法,就是类内部的函数。
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sexdef run(self):
print("我是{0},我可以跑步".format(self.name))
除了跑步以外,学生还具备跳高动作,继续增加一个类方法
class Student:
def __init__(self, name, sex):
self.name = name
self.sex = sexdef run(self):
print("我是{0},我可以跑步".format(self.name))def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))
到此为止,一个
Student
类就已经定义完毕了,可以拿着这个设计图去实例化学生了。xiao_ming = Student("小明", "男")
xiao_hong = Student("小红", "女")xiao_ming.run()
xiao_hong.jump()
在类的定义过程中,内部的方法(函数)第一个关键字一定不要丢掉。
属性转为私有属性
在 python 中有个约定俗称的规则,在属性或者方法名称前,增加一个下划线
_
,表示该属性或者方法仅在类的内部使用。class Student:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self._age = agedef run(self):
print("我是{0},我可以跑步".format(self.name))def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))xiao_ming = Student("小明", "男", 19)
xiao_hong = Student("小红", "女", 20)xiao_ming.run()
xiao_hong.jump()# 调用私有属性,可以掉到,但是请遵守约定规则
print(xiao_hong._age)
上述代码,你可以手动的去调用
_age
,从而获取到 age
属性,更加严格的办法是在属性或者方法前增加两个下划线 __
,此时手动调用属性无法获取。class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weightdef run(self):
print("我是{0},我可以跑步".format(self.name))def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))xiao_ming = Student("小明", "男", 19, 180)
xiao_hong = Student("小红", "女", 20, 90)xiao_ming.run()
xiao_hong.jump()# 调用私有属性,可以掉到,但是请遵守约定规则
print(xiao_hong._age)# 无法调用两个下划线的属性
print(xiao_hong.__weight)
错误提示如下所示
AttributeError: 'Student' object has no attribute '__weight'
这里真实的情况也是无法避免被调用,只是增加两个下划线之后,名称在内部被置换成其它名称了,看上去是被隐藏掉了。
继承类以及面向对象的高级特征 在 python 中编写类之后,有时需要给类扩展功能,此时最直接的办法就是继承类。
类的继承就是以某一个类为基类来制作新的类。这里的基类也叫做超类,继承自超类创建的类,为子类。
Python 支持多重继承,将多个类组合成一个新的类。
类继承的语法格式如下(包括多重继承)
class 类名称(超类1,超类2,超类3,...):
pass
在子类中可以对超类的方法进行重写,简单理解就是在子类重新定义一个与超类同名的方法。
class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weightdef run(self):
print("我是{0},我可以跑步".format(self.name))def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))class Mid_Student(Student):
# 重写超类方法
def run(self):
print("我重新了超类的 run 方法")xiao_ming = Student("小明", "男", 19, 180)
xiao_hong = Mid_Student("小红", "女", 20, 90)# 调用子类的 run Fangfa
xiao_hong.run()
在子类的初始化方法中,可以调用超类的初始化方法
该处关键词为
super
,使用 super
调用超类方法是由于在 python 中,重写方法是完全覆盖原有内容,例如下述代码:class Student:
def __init__(self, name, sex, age, weight):
self.name = name
self.sex = sex
self._age = age
self.__weight = weightdef run(self):
print("我是{0},我可以跑步".format(self.name))def jump(self):
print("我是{0},{1}生,可以跳高".format(self.name, self.sex))class Mid_Student(Student):
# __init__ 方法将超类中的初始化方法完全覆盖
def __init__(self, card_id):
self.card_id = card_iddef run(self):
print("我重新了超类的 run 方法")xiao_hong = Mid_Student(10086)# 报错,没有该属性
print(xiao_hong.name)
如果希望继续使用超类的属性,可以使用
super
函数解决。class Mid_Student(Student):
def __init__(self, name, sex, age, weight, card_id):
# 通过 super 函数向 Student 类传参
super().__init__(name, sex, age, weight)
self.card_id = card_iddef run(self):
print("我重新了超类的 run 方法")xiao_hong = Mid_Student("小红", "女", 19, 100, 10086)print(xiao_hong.name)
【滚雪球学Python第四轮|10. python入门速通教程之类、继承类、类中的特殊方法】在 python 中是可以给对象实例任意添加属性的,例如下述代码:
class MyClass:
passc = MyClass()
c.name = "橡皮擦"print(c.name)
那是否存在限制任意添加属性的办法呢?有的。
使用
__slots__
属性即可限制属性的添加。class MyClass:
__slots__ = ['name', 'age']
passc = MyClass()
c.name = "橡皮擦"
c.age = 19
c.sex = "女"print(c.name)
运行代码会出现如下错误:
AttributeError: 'MyClass' object has no attribute 'sex'
。类中的特殊方法 在上文提及的
__init__
是类的初始化方法,与之相同的还有一些其它特殊方法。__add__
和__iadd__
:当对象使用+
和+=
运算符时,被调用;__sub__
和__isub__
:当对象使用-
和-=
运算符时,被调用;__mul__
和__imul__
:当对象使用*
和*=
运算符时,被调用;_truediv__
和itruediv
:当对象使用/
和/=
运算符时,被调用;
__floordiv__
和 __ifloordiv__
,__and__
,__or__
,这些都可以算作类内部定义算术运算符。比较运算符也可以在类内部进行重定义。
__eq__
:使用==
运算符时,被调用;__ne__
:使用!=
时被调用;__lt__
:使用<
被调用;__gt__
:使用>
被调用;
__int__
:被内置函数int()
调用时使用的方法;__float__
:被内置函数float()
调用时使用的方法;__str__
:被str()
调用时使用的方法;__repr__
:返回对象的字符串表示方法;__bytes__
:被bytes()
调用时使用的方法;__format__
:被format()
格式化字符串时用到的方法。
__len__
:调用len()
函数时使用;__getitem__
:如果想让对象具备按索引获取的形式,定义该方法;__setitem__
:通过索引设置值;__delitem__
:使用del
删除对象中元素时,被调用;__iter__
:被iter
等迭代类代码调用时;__contains__
:使用in
运算符时被调用。
__call__
:将对象向函数一样调用;__del__
:删除对象时被调用;__hash__
:使用hash
函数时被调用。
今天是持续写作的第 226 / 365 天。更多精彩
期待 关注,点赞、评论、收藏。
- 滚雪球学 Python(完结)
- 滚雪球学 Python 第二轮(完结)
- 滚雪球学 Python 第三轮
- 滚雪球学 Python 番外篇(完结)
推荐阅读
- 慢慢的美丽
- 开学第一天(下)
- 奔向你的城市
- 学无止境,人生还很长
- 由浅入深理解AOP
- “成长”读书社群招募
- 继续努力,自主学习家庭Day135(20181015)
- python学习之|python学习之 实现QQ自动发送消息
- 每日一话(49)——一位清华教授在朋友圈给大学生的9条建议
- 小影写在2018九月开学季