有人整个 Python 学习生涯都没有搞明确的技术之一:面向对象。

Python 面向对象的编程

Python 精确的说也是一门面向对象编程的语言,简称 OOP,咱曾经晓得在 Python 中所有的数据类型都是对象,除了 Python 设置好的以外,Python 容许程序开发者本人定义数据类型,这种由程序员自定的数据类型就是

面向对象初学有门槛,学习请审慎。

类的定义与应用

类的定义语法格局如下:

class MyClass():    代码块    ...    代码块

类名的第一个字母倡议大写,例如语法格局中的 MyClass

定义类、属性与办法

类的外部蕴含属性与办法,接下来咱定义一个 “人” 类。

# 定义人类class Person():    # 类的属性    name = "迪迪"    # 类的办法    def talk(self):        print("say hello")

在上述代码中,Person 是类名称,在这个类中定义了一个属性与一个办法。类的外部定义方法与函数十分类似,然而留神在类外部定义的函数可不能在称为函数了(是不是开始绕了),要叫做办法,因为只有类的对象才能够调用该办法
办法定义时留神有一个参数为 self,牢记为固定写法,在所有类外部的办法参数中,都要写上 self 这个关键字。

属性与办法的调用

在调用属性与办法之前,必须先定义一个类的对象,具体形式如下,这个操作也叫做 实例化,类的实例化操作之后就呈现了对象。

对象 = 类名()

例如方才曾经定义好了一个人类,应用下述代码能够获取一个人类的对象。

# 定义对象xiang = Person()

对象定义结束就能够应用属性与办法了。

class Person():    # 类的属性    name = "迪迪"    # 类的办法    def talk(self):        print("say hello")xiang = Person()# 输入对象print(xiang)# 输入对象的属性print(xiang.name)# 输入对象的办法xiang.talk()

代码运行之后,输入如下内容。

<__main__.Person object at 0x000002465F364B70>迪迪say hello

代码中的变量 xiang 就是 Person 类的一个对象,通过 xiang 对象能够读取 Person 类内的 name 属性与 talk 办法。

如果类还有其它的属性与办法,应用雷同的形式即可实现。

类的构造函数

难度上在调高一点,建设类的同时心愿初始一些数据进去,也就是初始化类,该内容是在类的外部编写一个办法,这个办法是一个非凡的办法,在编程的过程中定义类的对象将主动执行这个办法。

初始化办法名称是固定的 __init__,该办法在 init 左右各有两个下划线。类的初始化办法称为 构造函数(刚说了类外面叫做办法,本人就叫函数了,是不是迷糊了,这个还真没方法,大家都这么叫)。

接下来编写一个代码,当定义一个类的对象时候,默认给 Person 类的属性 name 赋值。

class Person():    # 类的属性    name = "迪迪"    # 构造函数    def __init__(self, in_name):        self.name = in_name    # 类的办法    def talk(self):        print("say hello")xiang = Person('teacher')# 输入对象print(xiang)# 输入对象的属性print(xiang.name)# 输入对象的办法xiang.talk()

上述代码做了一些简略的变动,首先退出了 __init__ 构造函数,留神构造函数的参数有两个,一个是 self,这个在类外部定义函数的时候是必须的,并且须要放在参数的最右边,Python 在定义一个类的对象的时候会主动传入这个参数 selfself 代表的类自身的对象。

构造函数中还有一个参数 in_name,如果设计了构造函数,并且有除了 self 以外的其它参数,那在定义 Person 对象的时候,必须传递该参数,传递进来的该参数通过 self.name 能够批改对象的属性。

说起来很绕,简略外面就是每次当咱们用类定义一个对象的时候,例如下述代码:

obj1 = Person()obj2 = Person()

下面定义了两个对象,都是根据类 Person 定义的,self 这个参数在类的外部就示意具体是哪个对象。

如果还不了解,没有问题,记住上面的话。

类申明之后,相当于你本人定义了一个数据类型,你能够应用该种数据类型的变量,只是因为面向对象的概念,把这个变量叫做对象了,对象能够调用类的属性和办法,一个类对应多个对象,那如何判断具体是哪个对象在调用类外部的属性或者办法呢,须要用到的就是 self 这个参数。

属性初始值

在本局部之前,在类外部设定一个初始值,间接用 name = "迪迪" 来实现了,学习完构造函数之后,你应该理解到通常在 Python 初始化数据时,个别放在 __init__ 办法内。

class Person():    # 构造函数    def __init__(self, in_name, in_age):        # 属性的初始化        self.name = in_name        self.age = in_age    # 类的办法    def talk(self):        # 类中的属性,在初始化之后能够通过 self.name 调用        print(self.name)        print("say hello")    def show_age(self):        # 通过 self.age 调用初始化的年龄        print(self.age)xiang = Person('teacher', 19)# 输入对象print(xiang)# 输入对象的属性print(xiang.name)# 输入对象的办法xiang.talk()

封装

接下来要学习的是面向对象的三个基本特征之一,封装。

封装简略了解就行,先不要钻进去,了解概念,了解概念。

方才咱们应用的属性与办法都能够通过对象在类的内部拜访,这些叫做私有属性与私有办法,但有些时候类外部的属性和办法不心愿被内部对象进行批改,须要引入公有属性与公有办法相干概念,这种概念的引入导致了封装概念的呈现。

封装就是封住类外部的货色,不叫你轻易用(其实是有方法能够调用到的)。

公有属性

在类外部定义公有属性非常简单,是写作上的技巧,只须要在属性后面加上两个下划线即可,即 __name

例如在人类中定义一个机密变量为公有属性。

class Person():    # 构造函数    def __init__(self, in_name, in_age):        # 属性的初始化        self.name = in_name        self.age = in_age        self.__secret = "我有代码洁癖" # 公有属性    # 类的办法    def talk(self):        # 类中的办法,能够拜访到公有属性        print(self.__secret)        print("say hello")    def show_age(self):        print(self.age)xiang = Person('teacher', 19)# 尝试输入对象的公有属性print(xiang.__secret)  # 报错# 尝试通过类的办法输入公有属性xiang.talk()

类的外部初始化好公有属性之后,通过对象.属性名发现无奈调用到公有属性,然而在类的外部是能够应用公有属性的,这种操作就叫做封装属性。

公有办法

有公有属性,必然有公有办法,这两个模式一样的,在办法后面加上两个下划线,就是公有办法了。

class Person():    # 构造函数    def __init__(self, in_name, in_age):        # 属性的初始化        self.name = in_name        self.age = in_age        self.__secret = "我有代码洁癖" # 公有属性    # 类的办法    def talk(self):        # 类中的办法,能够拜访到公有属性        print(self.__secret)        print("say hello")    # 类的公有办法    def __show_age(self):        print(self.age)xiang = Person('teacher', 19)# 尝试输入对象的公有属性# print(xiang.__secret)  # 报错# 尝试通过类的办法输入公有属性xiang.__show_age() # 报错

留神报错的内容,能记住就记住,纯熟的找到代码谬误的前提就是你碰到的代码谬误足够多。

继承

学习继承概念以前,有几个新词须要学习一下,首先类是能够继承的,其中被继承的类称为父类或者基类,继承的类称为子类或者衍生类。应用类继承最大的益处就是,父类实现的私有属性或者办法在子类中不必从新设计了。

该内容也是说起来迷糊,先看一下语法格局。

# 定义个父类class BaseClassName():    父类的代码块class ChildClassName(BaseClassName):    子类的代码块

继承类的时候,括号内搁置父类的名称。

继承的简略利用

申明一个动物类,而后让狗类继承动物类。动物类有一个私有属性叫做 name,一个私有办法叫做 sleep

# 定义 Animal 类class Animal():    def __init__(self):        self.name = "动物名称"    def sleep(self):        print("动物都会睡觉")# Dog 类继承自 Animal 类class Dog(Animal):    passdog = Dog()print(dog.name)dog.sleep()

上述代码中的 Dog 类没有任何属性与办法,只是继承了 Animal 类,就领有了 Animal 类的私有属性与私有办法。

该继承形式,子类无奈间接读取父类的公有属性或者办法,也就是下述代码是谬误的。

# 定义 Animal 类class Animal():    def __init__(self):        self.name = "动物名称"        self.__secret = "机密"    def sleep(self):        print("动物都会睡觉")# Dog 类继承自 Animal 类class Dog(Animal):    passdog = Dog()print(dog.__secret)dog.sleep()

子类与父类有雷同名称的属性或办法

在程序编写的时候,子类也能够有本人的初始化办法,即 __init__ 办法,在这种状况下会呈现子类中的属性名、办法名与父类雷同的状况,此时请以子类中的属性值或办法为主。

# 定义 Animal 类class Animal():    def __init__(self):        self.name = "动物名称"        self.__secret = "机密"    def sleep(self):        print("动物都会睡觉")# Dog 类继承自 Animal 类class Dog(Animal):    def __init__(self):        self.name = "狗"    def sleep(self):        print("狗会睡觉")# 父类的对象animal = Animal()animal.sleep()# 子类的对象dog = Dog()dog.sleep()

该内容如果扩大开来就是面向对象的三大特色的最初一个 -- 多态

子类用父类的办法

应用 super 函数能够在子类中调用父类的办法,具体代码如下:

# 定义 Animal 类class Animal():    def __init__(self, a_name):        self.name = a_name        self.__secret = "机密"    def sleep(self):        print("动物都会睡觉")    def show(self):        print("当初传递进来的名称为" + self.name)# Dog 类继承自 Animal 类class Dog(Animal):    def __init__(self, a_name):        # 调用父类对象的一般办法        # super().sleep()        super().__init__("动物名称" + a_name)# 父类的对象animal = Animal("一般动物")animal.show()# 子类的对象dog = Dog("大狗狗")dog.show()

Dog 类的构造函数中通过 super().__init__("动物名称" + a_name) 批改了传递给父类的参数,此计划相当于通过 super 函数生成一个父类的对象,而后在调用父类的 __init__ 办法,实现对父类的初始化操作。

多态

多态简略了解是说父类与子类有雷同办法,通过父类、子类创立出的对象调用雷同的办法名呈现不同的后果。更多时候多态是程序会依据对象主动去调用指定的办法,该内容具体代码实现如下:
首先定义一个函数,这个函数有一个参数即可。

def gogo(obj):    obj.say()

该函数的参数能够为任意数据类型的对象,而后在定义两个类,这两个类中需都存在 say 办法。

class Dog():    def say(self):        print("汪汪汪")class Cat():    def say(self):        print("喵喵喵")# 该函数会通过传进的对象进行判断是调用哪个办法。def gogo(obj):    obj.say()# 通过 Dog 定义一个对象dog = Dog()# 通过 Cat 定义一个对象cat = Cat()# 在 gogo 函数中传递 dog 对象gogo(dog)# 在 gogo 函数中传递 cat 对象gogo(cat)

以上代码当传入函数体外部的对象更换时,输入的数据不同,这种编码的模式或者叫编码的设计思路就是多态的一种展现。

简略了解就是 同一办法因对象不同导致实现内容不同

多重继承

上文解说的都是繁多继承关系,在理论编码中很多时候会用到多重继承,就是一个类继承多个父类,语法结构如下:

class 子类名称(父类1,父类2,父类3...):    类的代码块

该内容不再进行扩大开解说,在多重继承的时候,记住一句话就行,写在后面的父类比写在前面的父类优先级要高,也就说如果父类中都呈现了同一个办法,那子类优先选择后面的父类,即下面语法格局中的 父类1

对象的数据类型判断

应用 type 函数能够判断某对象的数据类型,例如下述代码:

class Dog():    def say(self):        print("汪汪汪")class Cat():    def say(self):        print("喵喵喵")# 通过 Dog 定义一个对象dog = Dog()# 通过 Cat 定义一个对象cat = Cat()print(type(dog))print(type(cat))

输入内容为:

<class '__main__.Dog'><class '__main__.Cat'>

type 能够获取到对象的起源类。

isinstance 函数

isinstance 函数能够判断对象是否属于某一个类,语法格局如下:

isinstance(对象,类) # 如果对象是由类实例化而来,返回 True,否则返回 Flase

该函数能够判断出一个对象是否实例化自父类。

# 父类class Animal():    pass# 子类class Dog(Animal):    def say(self):        print("汪汪汪")# 子类class Cat(Animal):    def say(self):        print("喵喵喵")# 通过 Dog 定义一个对象dog = Dog()# 通过 Cat 定义一个对象cat = Cat()print(isinstance(dog,Dog)) # Trueprint(isinstance(dog,Animal)) # Trueprint(isinstance(cat,Animal)) # True

非凡属性、办法

在之前的课程中,应用 dir 函数作用于某一对象,会失去如下内容。

该内容存在大量的 __XXXX__ 的内容,这些就是一个对象中非凡的属性与办法。

接下来列举几个。

__doc__ 获取文档字符串

如果一个类中申明了文档字符串,就是在类的开始用 """ 三引号定义了一些内容,例如下述代码:

class Animal():    """"    我是文档字符串,相当于一个类的阐明局部,其实我有规范的格局    橡皮擦在第一遍滚雪球的时候,就是不违心写    """    passanimal = Animal()print(animal.__doc__)

__name__ 属性
这里留下一个思考题,就是自行查阅 __name__ 属性是干啥的,如果了解了,当前看到上面的代码不会问为什么。

if __name__ == '__main__':    执行某些代码

非凡办法局部在第一遍滚雪球的时候,不必费劲去学习了,段位还没到,学了和没学一样,如果感觉非学不可,恰好是一个求索常识的机会,这时的学习会事倍功半的。

想学习能够自行找材料,关键词为 __str__()__repr__()__iter__()

这篇博客的总结

面向对象,对于编程初学者来说,这个货色学了跟没学一样,你要深信不只是你无奈在第一遍学习的时候就齐全把握,99%的人都一样,保持就对了,先晓得在 Python 中也有类,也有对象就够了,工夫是学习最大的利器,打卡,打卡,每天学那么一点点,3 个月后见。

最初一碗毒鸡汤

前女友和我离别有两个起因,一是我过后没什么钱,二是她猜到了我未来也不会有什么钱。 O(∩\_∩)O 哈哈~