10. python入门速通教程之类、继承类、类中的特殊方法

举报
梦想橡皮擦 发表于 2021/09/29 16:09:46 2021/09/29
【摘要】 python 学习过程中,对新手来说,最难的就是面向对象部分了,但又不得不把它掌握。在 python 中所有的内容都是对象 python 中的类学习面向对象,第一个知识点就是类,它可以看成是对象的设计图,通过提炼各种相似对象的属性和方法,然后形成一个“模板”,就是类。在正式开始前,一定要明确一个类可以实例化出多个对象实例,这句话中也包含了,对象、实例、类之间的关系,一定要理解清楚。==类是在...

python 学习过程中,对新手来说,最难的就是面向对象部分了,但又不得不把它掌握。

在 python 中所有的内容都是对象

python 中的类

学习面向对象,第一个知识点就是类,它可以看成是对象的设计图,通过提炼各种相似对象的属性和方法,然后形成一个“模板”,就是类。

在正式开始前,一定要明确一个类可以实例化出多个对象实例,这句话中也包含了,对象、实例、类之间的关系,一定要理解清楚。

==类是在程序中实例化对象的设计图==

类的定义
使用关键字 class 定义类,class 后面为类名,类名一般采用驼峰命名法,即 MyClass,单词首字母大写。

class MyClass:
    pass


c = MyClass()
c.name = "橡皮擦"
print(c.name)

类的调用与函数类似,使用 类名() 即可,上述 MyClass 是一个空白类(设计图),调用类之后赋值给变量 c,此时的 c 就是类的一个实例对象,一般简称为实例或对象。

使用点号 .,可以给对象添加属性,每个对象都可以添加自己的属性。

当然一个类可以实例化出多个对象

class MyClass:
    pass


c1 = 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 = name


c = 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 = sex

    def run(self):
        print("我是{0},我可以跑步".format(self.name))

除了跑步以外,学生还具备跳高动作,继续增加一个类方法

class Student:
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex

    def 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 = age

    def 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 = weight

    def 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 = weight

    def 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 = weight

    def 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_id

    def 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_id

    def run(self):
        print("我重新了超类的 run 方法")


xiao_hong = Mid_Student("小红", "女", 19, 100, 10086)

print(xiao_hong.name)

在 python 中是可以给对象实例任意添加属性的,例如下述代码:

class MyClass:
    pass


c = MyClass()
c.name = "橡皮擦"

print(c.name)

那是否存在限制任意添加属性的办法呢?有的。
使用 __slots__ 属性即可限制属性的添加。

class MyClass:
    __slots__ = ['name', 'age']
    pass


c = 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 天。
期待 关注点赞评论收藏

更多精彩

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。