【Python基础篇017】6000字带你初识面向对象

41 阅读10分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第32天,点击查看活动详情


** 📚前言**

✅本次讲解的是Python的面向对象,面向对象是什么? 学面向对象的好处是什么? 如何创建一个对象 ? 面向对象需要掌握的方法是什么? 对象和类的关系又是什么? 看完这篇文章你或许会有所收获

文章目录

📚前言

📕一、面向对象和面向过程异同

📄1、面向过程

📄2、面向对象

📕二、类的相关知识

📕三、类的相关操作方法

📄1、定义类

📜1.1、说明

📄2、创建和使用对象

📜2.1、实例化一个对象

📜2.2、访问属性

📄3、总结类与对象的关系

📜3.1、类的总结

📜3.2、类和对象的区别

📕四、类中一些规则解释

📄1、关于__init__函数与它的参数self

📄2、知识点拓展

📜2.1、init()要点如下

📕五、类属性的补充

📄1、__slots__​​

📄2、​​__doc__​​

📄3、​​__module__​​

📄4、​​__class__

📄5、​​__dict__​​

📄6、​​__dir__()​​

📄7、​​__setitem__​​方法

📄8、​​__getitem__​​方法

📄9、​​__delitem__​​方法

📚结语

📕一、面向对象和面向过程异同

📄1、面向过程

  1. 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤。

  2. 面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。

  • 优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
  • 缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
  • 应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

📄2、面向对象

面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。

当下的程序员应该都听过"面向对象编程"一词,也经常有人问能不能用一句话解释下什么是"面向对象编程",我们先来看看比较正式的说法。

"把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。"

  • 优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
  • 缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
  • 应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。

📕二、类的相关知识

在讲类之前需要了解一些名词:类、对象、实例、实例化

  • 类:具有相同特征的一类事物(人、狗、老虎)
  • 对象/实例:具体的某一个事物比如小狗类中的旺财(特指某一条狗)
  • 实例化:类——>对象的过程

📕三、类的相关操作方法

📄1、定义类

在Python中可以使用class关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。

比如创建一个Dog类,为即将创建的所有狗对象绑定name和age两个属性,并且赋予每条创建的狗坐下( set() )的能力

class Dog:#创建一个狗类
    role = 'dog'  # 狗的角色属性都是狗

    # __init__是一个特殊方法用于在创建对象时进行初始化操作
    # 通过这个方法我们可以为狗对象绑定name和age两个属性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sit(self):
        '''模仿小狗接到命令(对象调用该函数)时坐下'''
        print('小狗已经坐下了')

📜1.1、说明

写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。

📄2、创建和使用对象

📜2.1、实例化一个对象

实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。 以下使用类的名称Dog来实例化,并通过 init 方法接收参数。

上面我们创建了一个狗类,但是要实例化一条实实在在的独一无二的狗那该怎么操作呢?

实例化一只实实在在的旺财

wc = Dog('旺财' , 1)  #创造了一只具体的狗(旺财)

📜2.2、访问属性

您可以使用点号 . 来访问对象的属性。使用如下类的名称访问类变量

创建完了旺财,上面不是说了为即将创建的所有狗对象绑定name和age两个属性,那我想查看我创建的旺财的属性(name,age)该怎么办呢?往下看

print(wc.name)
print(wc.age)

输出结果:
旺财
1

有人会说上面我们创建的Dog类赋予每条创建的狗坐下( set() )的能力,那么我家的旺财应该也有这种能力,那么就用以下方法使旺财展示这种能力

#使旺财坐下
wc.sit()

输出结果:
小狗已经坐下了

📄3、总结类与对象的关系

📜3.1、类的总结

类与对象是整个面向对象中最基础的组成单元。

类:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);

对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。

📜3.2、类和对象的区别

类是对象的模板,对象是类的实例。类只有通过对象才可以使用,而在开发之中应该先产生类,之后再产生对象。类不能直接使用,对象是可以直接使用的,用通俗的话来说在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个(比如上面我创建的旺财是实例化了一条独一无二的狗)。

📕四、类中一些规则解释

📄1、关于__init__函数与它的参数self

上面我是这样创建一个Dog类的

class Dog:#创建一个狗类
    role = 'dog'  # 狗的角色属性都是狗

    # __init__是一个特殊方法用于在创建对象时进行初始化操作
    # 通过这个方法我们可以为狗对象绑定name和age两个属性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sit(self):
        '''模仿小狗接到命令(对象调用该函数)时坐下'''
        print('小狗已经坐下了')

我们可以发现类里面有这样一个__init__函数,每次创建类的实例对象时, __init__函数就会自动被调用,无论它里面有什么样的变量、计算,统统会自动调用。

理解__init__函数需要搞清楚以下三点:

  • 1、带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问
  • 2、init函数(方法)支持带参数的类的初始化 ,也可为声明该类的属性
  • 3、init函数(方法)的第一个参数必须是 self(self为习惯用法,也可以用别的名字),后续参数则可 以自由指定,和定义函数没有任何区别。

至于它的参数必须叫做self吗?

在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字,但是正常人都不会这么做。

📄2、知识点拓展

📜2.1、init()要点如下

  • 1.名称固定,必须为__init__()
  • 2.第一个参数固定,必须为self。self指的就是刚刚创建好的示例对象。
  • 3.构造函数通常用来初始化示例属性,如下代码就是初始化示例属性:
  • 4.通过类名(参数列表),来调用构造函数,调用后,将创建好的对象返回给相应的变量。
  • 5.init()方法:初始化创建好的对象,初始化指的是:"给实例属性赋值"
  • 6.new()方法:用于创建对象,但我们一般无需定义该方法。

📕五、类属性的补充

一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

📄1、__slots__​​

类中没有​​__slots__​​属性时,可以进行动态添加属性

class Dog(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


p = Dog('lucy', 18)
p.city = '上海'
print(p.city)  # 上海

当类中有​​__slots__​​​时,可以对属性进行控制。只可以设置​​__slots__​​中的属性,如果设置的属性不在范围内,会​报错​。

class Dog(object):
    __slots__ = ('name', 'age', 'sex')

    def __init__(self, name, age):
        self.name = name
        self.age = age


p = Dog('lucy', 18)
p.sex = '男'
p.city = '上海'  # 报错
print(p.sex)  # 男

📄2、​​__doc__​​

类的文档信息

class Person(object):
    """
    这是人的文档信息
    """
    __slots__ = ('name', 'age', 'sex')

    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('lucy', 18)
print(p.__doc__)  # 对象名.__doc__
print(Person.__doc__)  # 类名.__doc__


输出结果:

    这是人的文档信息
    

    这是人的文档信息

📄3、​​__module__​​

获取对象所在的模块
​test.py中的代码如下:​

class Person(object):
    __slots__ = ('name', 'age', 'sex')

    def __init__(self, name, age):
        self.name = name
        self.age = age

​demo.py中的代码:​

import test
p = test.Person('lucy', 18)
print(p.__module__)  # test

📄4、​​__class__

​​
获取对象的类名(全称​​__main__.类名​​)

class Person(object):
    __slots__ = ('name', 'age', 'sex')

    def __init__(self, name, age):
        self.name = name
        self.age = age


p = Person('lucy', 18)
print(p.__class__)   #<class '__main__.Person'>

输出结果:
<class '__main__.Person'>

📄5、​​__dict__​​

以字典的形式,显示对象所有的属性

class Person(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age


p = Person('lucy', 18)
print(p.__dict__)  # {'name': 'lucy', 'age': 18}

输出结果:
{'name': 'lucy', 'age': 18}

📄6、​​__dir__()​​

与​​dir(对象名)​​等价。查看一个对象支持的所有属性和方法

class Person(object):
    __slots__ = ('name', 'age')

    def __init__(self, name, age):
        self.name = name
        self.age = age


p = Person('lucy', 18)
print(p.__dir__())
print(dir(p))
print(set(p.__dir__()) - set(dir(p)))

输出结果

📄7、​​__setitem__​​方法

不能直接把一个对象当做字典来使用

class Person(object):
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
        
p = Person('张三', 18, '襄阳')
# 我想把age修改成20,会报错
p['age'] = 20  # [] 语法会调用对象的 __setitem__方法

利用​​__setitem__​​方法,可以进行修改和添加属性

class Person(object):
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city

    def __setitem__(self, key, value):
        self.__dict__[key] = value


p = Person('张三', 18, '襄阳')
p['age'] = 20
p['sex'] = '男'
print(p.__dict__)  # {'name': '张三', 'age': 20, 'city': '襄阳', 'sex': '男'}

print(p.age)

输出结果:
{'name': '张三', 'age': 20, 'city': '襄阳', 'sex': '男'}
20

📄8、​​__getitem__​​方法

getitem__的作用是什么呢?说白了就是类中一个特殊方法,类对象可以像字典对象那样根据key取值(dict['key']),如类对象Object['key'],系统会自动调用__getitem__方法(所以你在看pytorch里面Dataloader的时候没有发现主函数直接调用__getitem,原来是系统自动调用),然后返回该方法定义return值,说到这里,有一点需要强调哦, 字典取值时key不存在,会抛出异常,而类对象的key是否存在,都会调用__getitem__方法并返回其规定的值,下面进入实例。

class Person(object):
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city

    def __getitem__(self, item):
        return self.__dict__[item]

p = Person('张三', 18, '襄阳')
print(p['name'])  # 张三

输出结果:
张三

📄9、​​__delitem__​​方法

delitem(self,key):

这个方法在对对象的组成部分使用__del__语句的时候被调用,应删除与key相关联的值。同样,仅当对象可变的时候,才需要实现这个方法。

class Person(object):
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city

    def __delitem__(self, key):
        print(f'删除的属性{key}')

p = Person('张三', 18, '襄阳')
del p['city']   # 删除的属性city

输出结果:
删除的属性city