Python3.7学习笔记19-面向对象

Python3.7学习笔记19-面向对象

在我们日常开发中。程序设计方式大体分为2种。一种是面向过程,一种是面向对象。

一:面向对象

这种程序设计方式强调的是对象。类实例化对象之后。引用对象各种方法、属性的编程模式达到预期目的的过程。

1、下面我们用一个计算器的类来解释几个重要的概念


class Calculator(): # 如果不继承类。类名后面加不加括号都可以。默认加载object类
    """
    计算器类
    """

    # 类变量
    a = '+'
    b = '-'
    c = '*'
    d = '/'
    __siyou = '私有变量'  # 私有变量前面有2个下划线。只能类内部引用。

    # 实例化对象的时候会执行初始化函数
    def __init__(self, first_number, second_number):
        assert int(first_number), '输入的数必须为整数'
        assert int(second_number), '输入的数必须为整数'

        self.first_number = first_number  # 实例变量
        self.second_number = second_number  # 实例变量
        
    # 成员函数
    def variable(self):
        """
        演示局部变量和私有变量
        :return:
        """
        text = '局部变量'
        return (text + Calculator.__siyou)

    def addition(self):
        """
        加法函数
        :return:
        """
        print('调用了' + Calculator.a + '运算')  # 类名引用类变量
        return (self.first_number + self.second_number)

    def hair_reduction(self):
        """
        减法函数
        :return:
        """
        print('调用了' + self.b + '运算')  # 实例化引用类变量
        return (self.first_number + self.second_number)


calculator_object = Calculator(1, 2)  # calculator_object 类的实例化对象
print(calculator_object.addition())  # 引用对象加法运算
print(calculator_object.variable())  # 引用对象函数
print(calculator_object.a)  # 访问对象类变量
# print(calculator_object.__siyou)  # 访问对象私有变量是会报错的
calculator_object.test='新增类的一个属性'
calculator_object.b = '修改类的一个属性值'
print(calculator_object.test,calculator_object.b) # 访问对象的2个静态属性
print(calculator_object.hair_reduction()) # 引用对象的减法函数
  • 类(class):一群有着相同属性和函数的对象的集合。对象是类的实例。Calculator是类名。如上图所示。当实例化创建对象之后。对象拥有各种函数,各种属性。就像一个集合里面放着各种各样的函数和各种各种各样的属性一样。
  • 方法:类中定义的函数。如variable,addition,hair_reduction它们称为类的成员函数。还有类函数,静态函数。(下个代码演示会有)
  • 对象:类实例化的一个对象。比如 calculator_object
  • 属性:对象的某个静态特征 。主要有两类:                                                                                                                                类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使 用。如a,b,c,d 。实例化对象之后可以访问也可以修改(虽然可以这样操作。但是一般情况下设置类变 量都是为了内部函数使用)。__siyou 变量前面加2个下划线。只能在类内部使用。调用类变量有2种方式。一种是类名.变量名。另外一种self.变(self==实例化对象)                                                                                                                                                                                   实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量

2、类中的函数,主要分为以下四种。

  • 成员函数:第一个参数是self (类的实例)的函数。在外部引用时候一定要先初始化对象才可以引用。
  • 静态函数:个人认为就是一个类的伪函数。为什么这么说尼。因为这个函数和类本身没有任何关系。可以没有参数在有参数的时候也不需要第一个参数是self。简单理解就是成员函数需要使用它。但是又不想单独在类外面写一个函数。所以就把这个函数也放到类里面了。定义静态函数需要加上装饰器@staticmethod(后面单独学习这个)。其他函数要引用它的时候。可以当着是一个成员函数来使用。self.函数名。但是要记住静态函数是不能引用类里面的其他的函数和变量
  • 类函数:定义类函数也要加上装饰器@classmethod。它和成员函数的区别有2个。第一。参数是cls指向类本身。第二外部引用该函数时不需要实例化对象。如演示代码所示。可以直接引用该类函数
  • 私有函数。函数名称前面有2个下划线。该函数只能在类内部调用。实例化的对象是不能引用的
# -*- coding: utf-8 -*-
# @Time   : 2020/4/14 22:08
# @Author : linglong
# @File   : demo.py


class Calculator():
    """
    计算器类
    """

    # 类变量
    a = '+'
    b = '-'
    c = '*'
    d = '/'

    # 实例化对象的时候会执行初始化函数
    def __init__(self, first_number, second_number):
        assert int(first_number), '输入的数必须为整数'
        assert int(second_number), '输入的数必须为整数'

        self.first_number = first_number  # 实例变量
        self.second_number = second_number  # 实例变量

    # 类函数
    @classmethod
    def update_obj_variable(cls, update_first_number, update_second_number):
        """
        构造不一样__init__函数初始化的实例变量值
        :return:
        """

        return cls(first_number=update_first_number, second_number=update_second_number)

    # 静态函数
    @staticmethod
    def return_print(operation):
        """
        返回使用运算方式
        :param operation:
        :return:
        """

        return ('调用了' + operation + '运算')

    # 成员函数
    def addition(self):
        """
        加法函数
        :return:
        """
        print(self.return_print(Calculator.a))  # 引用静态函数

        return (self.first_number + self.second_number)

    # 成员函数
    def hair_reduction(self):
        """
        减法函数
        :return:
        """
        print(self.return_print(Calculator.b))  # 引用静态函数

        return (self.first_number + self.second_number)


calculator_object = Calculator.update_obj_variable(1, 2)  # 引用类函数不需要初始化对象。
print(calculator_object.addition())  # 引用对象加法运算
calculator_object.first_number = 3  # 修改实例变量的值
calculator_object.second_number = 4  # 修改实例变量的值
print(calculator_object.hair_reduction())  # 引用对象加法运算

3、类的专有方法

除了第一个比较常用之外。其他的感觉没咋用过。

  • __init__ : 构造函数,在生成对象时调用
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__: 按照索引获取值
  • __len__: 获得长度
  • __cmp__: 比较运算
  • __call__: 函数调用
  • __add__: 加运算
  • __sub__: 减运算
  • __mul__: 乘运算
  • __truediv__: 除运算
  • __mod__: 求余运算
  • __pow__: 乘方

class Mylist:
    __mylist = []

    def __init__(self, *args):
        self.__mylist = []
        for arg in args:
            self.__mylist.append(arg)

    def __str__(self):

        return '打印实例化对象的时候返回的就是这个'

    def __add__(self, n):
        """
        对象和一个数相加。就会执行该方法。其他同理。
        :param n:
        :return:
        """
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] + n

    def __sub__(self, n):
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] - n

    def __mul__(self, n):
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] * n

    def __div__(self, n):
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] / n

    def __mod__(self, n):
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] % n

    def __pow__(self, n):
        for i in range(0, len(self.__mylist)):
            self.__mylist[i] = self.__mylist[i] ** n

    def __len__(self):
        return len(self.__mylist)

    def show(self):
        print(self.__mylist)


l = Mylist(1, 2, 3, 4, 5)
print(l)
l.show()
l + 5
l.show()
l - 3
l.show()
l * 6
l.show()
l % 4
l.show()
l ** 3
l.show()
print(len(l))
b = Mylist(2, 3, 4, 5, 6, 7, 8, 9)
print(len(b))
b.show()
b - 5
b.show()
l.show()

4、类的继承

  • 单继承。如下图所示。当新建一个类的时候。类名后面跟着的括号输入另外一个类的名称。括号内的类是该类的父类,父类的所有方法和属性都会被新类继承。可以直接引用。需要注意的是,当父类有构造函数__init__。继承类需要在自己的构造函数里面显示的调用父类的构造函数。(不要使用父类名称.__init__(self,first_number,second_number)  这种写法。因为当有多层继承的时候会出问题。记住用这个函数即可  super().__init__(first_number, second_number)  )。当需要重写父类的方法时。只需要在子类新建一个名字一样的函数。在对象引用的时候就只会调用重写的函数。
# -*- coding: utf-8 -*-
# @Time    : 2020-04-20 22:11
# @Author  : zhonglinglong
# @File    : demo.py

"""

"""


# 父类
class Calculator():
    """
    计算器类
    """

    # 类变量
    a = '+'
    b = '-'
    c = '*'
    d = '/'

    # 实例化对象的时候会执行初始化函数
    def __init__(self, first_number, second_number):
        assert int(first_number), '输入的数必须为整数'
        assert int(second_number), '输入的数必须为整数'

        self.first_number = first_number  # 实例变量
        self.second_number = second_number  # 实例变量

    # 成员函数
    def addition(self):
        """
        加法函数
        :return:
        """
        print(self.return_print(Calculator.a))  # 引用静态函数

        return (self.first_number + self.second_number)

    # 成员函数
    def hair_reduction(self):
        """
        减法函数
        :return:
        """
        print(self.return_print(Calculator.b))  # 引用静态函数

        return (self.first_number + self.second_number)

    # 静态函数
    @staticmethod
    def return_print(operation):
        """
        返回使用运算方式
        :param operation:
        :return:
        """

        return ('调用了' + operation + '运算')


# 子类
class SubclassCalculator(Calculator):
    """
    子类继承计算机类
    """

    def __init__(self, first_number, second_number):
        super().__init__(first_number, second_number)  # 初始化父类的构造函数

    def multiplication(self):
        """
        乘法
        :return:
        """

        print(self.return_print(self.c))  # 引用静态函数

        return (self.first_number * self.second_number)

    # 子类重写父类方法
    def hair_reduction(self):
        """
        减法函数
        :return:
        """
        print('调用的是子类方法')
        print(self.return_print(Calculator.b))  # 引用静态函数

        return (self.first_number + self.second_number)


demo_object = SubclassCalculator(3, 2)
print(demo_object.multiplication())
print(demo_object.hair_reduction())
  • 多继承。如下所示。唯一需要注意的是构造函数的执行顺序是子类-父类-爷类-.-。而且切记构造父类的函数不能使用父类名.__init__(self)。有兴趣的可以去试试为什么不要这么写。
class A():
    def __init__(self):
        print('A')

class B(A):
    def __init__(self):
        print('B')
        super().__init__()

class C(A):
    def __init__(self):
        print('C')
        super().__init__()

class D(C):
    def __init__(self):
        print('D')
        super().__init__()

test = D()
  • 多重继承。指一个类同时继承了至少2个类的过程。除非很有必要且非常熟悉这种规则。否则实际工作当作尽量少使用这种用法。需要注意的是如果2个父类都有构造函数。那么该类在调用父类的构造函数中。只会执行括号第一个类。同理。如果2个父类的方法名称也是相同。在引用的时候。也只引用先加载的类。
    class AA():
        def __init__(self):
            print('AA')
    
        def get(self):
            print('A1')
    
    
    class BB():
        def __init__(self):
            print('BB')
    
        def get(self):
            print('B1')
    
    
    class DD():
        def __init__(self):
            print('DD')
    
    
    class CC(AA, BB, DD):
        def __init__(self):
            print('CC')
            super().__init__()
            self.get()
    
    
    t = CC()

     

  • 抽象类。其本质和一般的类没有多大区别。只不过是继承了metaclass=ABCMeta。当该抽象类函数有一个或者多个加了装饰器abstractmethod。该抽象类不能实例化。继承该类的子类必须对加了装饰器的函数进行重写。否则子类也不能实例化。抽象类常用在协同开发的时候。开发经理写API文档。比如要实现2个页面的后台接口开发。都拥有查询 新增 修改。还有2个页面不一样的接口。开发经理可以把相同的接口加上装饰器。其他接口只创建一个函数。描写清楚该函数要实现什么功能即可。然后2个不同的开发可以同时在自己的文件内继承该抽象类。对查询 新增 修改接口重新开发。然后对本来自己的功能接口按照描述重新编写。这样查看代码和开发代码的人很清楚的知道某个模块或者某个版本后台接口有那些。作用是什么。

from abc import ABCMeta, abstractmethod


class Calculator(metaclass=ABCMeta):
    """
    抽象类
    """

    def __init__(self):
        print('抽象类')

    # 加了该装饰器之后。该抽象类不能实例化。且继承的子类必须实现这个方法。
    @abstractmethod
    def addition(self):
        """
        加法函数
        :return:
        """
        print('加法')
        pass

    def hair_reduction(self):
        """
        减法函数
        :return:
        """
        pass


class A(Calculator):
    def __init__(self):
        print('继承抽象类')
        super().__init__()

    def addition(self):
        print('必须重写加了装饰器的抽象类的函数,否则实例化对象的时候一定报错')


a = A()
a.addition()

二:面向过程

面向过程:侧重的是过程。编程思想是准备好需要使用的函数和数据。然后按需求把函数和数字按照一定的顺序组合起来。

计算器的例子用面向过程实现的思想如下:

  • 我们分别创建了计算加减乘除的方法
  • 根据需求。把2个数字代入到方法中计算。

# 面向过程编程
def addition(first_number, second_number):
    assert int(first_number), '输入的数必须为整数'
    assert int(second_number), '输入的数必须为整数'

    print('调用了加法运算')
    return (int(first_number) + int(second_number))


def hair_reduction(first_number, second_number):
    assert int(first_number), '输入的数必须为整数'
    assert int(second_number), '输入的数必须为整数'

    print('调用了减法运算')
    return (int(first_number) - int(second_number))


def multiplication(first_number, second_number):
    assert int(first_number), '输入的数必须为整数'
    assert int(second_number), '输入的数必须为整数'

    print('调用了乘法运算')
    return (int(first_number) * int(second_number))


def division(first_number, second_number):
    assert int(first_number), '输入的数必须为整数'
    assert int(second_number), '输入的数必须为整数'

    print('调用了除法运算')
    return (int(first_number) / int(second_number))


a = 3
b = 4
print(addition(a, b))
print(hair_reduction(a, b))
print(multiplication(a, b))
print(division(a, b))

综述,面向过程和面向对象都能够实现同一功能。我们需要根据不同的场景来选择程序设计模式。一般来说。我们写个很小的工具或者实现某个单一固定的功能。因为不用担心代码复用维护的问题。还是推荐使用面向过程来实现。而当我们写项目级别的代码。尤其是协同开发。我们应该尽可能的通过分析需求。找出相似点。用一个或者几个类的形式实现。能够极大提高代码的复用率和代码维护效率。

 

 

你可能感兴趣的:(python学习笔记,python)