Python中的面向对象


说起面向对象,大家都不陌生,常用的Java就是一门面向对象的语言,但是很少人会觉得Python是一门

面向对象的语言,习惯使用Python的人更会觉得它有点像面向过程的语言,毕竟那流程化的操作让人觉得

是从哪里冒出来的对象啊,今天是时候为Python平反了,Python和Java都是面向对象的语言

但是我们所说的面向对象通常指的是编程的一种设计思想,更加准确的说应该是Python和Java都是支持

面向对象的语言,而且Python和Java都不是纯碎的面向对象,当然我们也不必过于纠结什么是纯碎。这篇

讲解一些Python中面向对象的一些特性

一、面向对象的主要特性

在面向对象编程中,函数和变量被进一步的封装成类,类是程序的基本元素,类和类的实例是面向对象

的核心概念,面向对象的主要编程框架如下:

  • 导入各种外部库

  • 设计各种全局变量

  • 决定你要的类

  • 给每个类提供完整的一组操作

  • 明确的使用继承来表现不同类的特点

  • 根据需要决定是否要写一个mian函数作为程序入口

面向对象中一些基础的概念是多态、继承、封装、抽象、类、对象、实例、方法、重载,下面对一些主要

的概念稍作解释

  • 类变量:所有实例公有的变量,类变量定义在类中,但是在方法体之外

  • 实例变量:是实例本身所拥有的变量,每个实例变量在内存都是不一样的

  • 静态方法:不需要实例化就可以由类指向的方法

  • 类方法:类方法是将类本身作为对象进行操作的方法

  • 重写:从父类继承的方法不能满足子类的需求,这个过程称为override

  • 封装:将内部实现包装起来,对外透明

  • 继承:子类继承父类的变量和方法

  • 多态:根据对象类型的不同以不同的方式进行处理

二、类与对象

1.类和对象的创建

Python中类和对象的创建是这样进行的

class test:
    classVar = "Test"  #类变量
    def __init__(self,para1,para2):   #理解为构造函数
        self.para1 = para1
        self.para2 = para2
    def fun1(self):              #类中的方法
        pass
    def fun2(self):
        pass

2.方法的调用

在类中方法主要有四类:实例方法、类方法、静态方法、属性方法

  • 实例方法:就是每个实例可以调用的方法,就是最普通的方法,一般会有一个self参数

  • 类方法: 只能访问类变量,不能访问实例变量,使用装饰器@classmethod表示

  • 属性方法:将一个方法变成一个静态属性,不同加小括号就可以直接调用的,使用装饰器@property表示

  • 静态方法:静态方法没有默认的参数,它将实例方法参数中的self去掉,然后在方法定义上加上@staticmethod,

就成为了静态方法,它属于类,与实例无关,建议只用类名.静态方法的调用方式。经常有一些跟类有关系

的功能但是运行时又不需要实例和类参与的情况下需要用到静态方法,比如更改环镜变量或者修改其他类的

属性等能用到静态方法

#静态方法使用示例
class Test:
    @staticmethod   #定义了一个静态方法
    def fun():
        pass
Test.fun()    #使用类直接去调用静态方法

#类方法使用示例
class Person(object):
    def __init__(self,name):
        self.name = name
    @classmethod
    def printMsg(self):
        print(self.name)    #self.name这个变量是实例化这个类是传进去的,类方法不能访问
    
class Person(object):
    name = "yzz"
    def __init__(self,name):
        self.name = name
    @classmethod
    def printMsg(self):
        print(self.name)    #类方法可以访问类变量
        
 #属性方法使用实例
class Person(object):
    def __init__(self,name):
        self.name = name
    @property
    def printMsg(self):
        print("Hello World")
per = Person("yzz")
per.eat                  #按照调用属性的方式调用

3.成员修饰符

Python中的类只有私有成员和公有成员两种,并且python中没有关键字去修饰成员,默认python中

所有的成员都是公有成员,私有成员是以两个下划线开头来标识的;私有成员不允许直接访问,只能通

过内部方法去访问,私有成员也不允许被继承

class Test:
    __age = 10 #私有变量
    def __init__(self,name,salary):
        self.name = name
        self.__salary = salary #私有变量
    def printName(self):
        print(self.name)
    #如果要在类中调用私有变量,应该使用类方法
    @classmethod
    def printMsg(cls):
        print(cls.__age,self.__salary)

三、类的主要特性

1.继承

在Python中的类可以继承多个类,但是Java只能继承一个类;Python中如果父类和子类都重新定义了

构造方法init(),在进行子类实例化的时候,子类的构造方法不会自动调用父类的构造方法,必须在子类中

显式地调用

#单继承
class DerivedClassName(BaseClassName1):
    pass
#基类定义在另一个模块中时
class DerivedClassName(modname.BaseClassName):
    pass

#多继承
class DerivedClassName(Base1,Base2,Base3):
    pass
#当父类中有相同方法名,但在子类中使用时未指定,Python会从左至右搜索父类是否包含该方法

2.方法重写

当Python中的父类方法功能不能满足时,子类中可以进行重写

class Parent:
    def printMsg(self):
        print("我是父类方法")
class Child(Parent):
    def printMsg(self):
        print("我是子类方法")
#super()函数就是调用父类方法的一个方法

3.反射和自省

Python中反射和自省的实现是通过一些魔法方法来实现的:hasattr、getattr、setattr、delattr四个内置函

数来实现的,这些方法在类和对象以及其他模块中用的都是比较多的,其中key都是字符串

  • hasattr(key): 返回的是一个bool值,判断某个成员或者属性是否存在于类或者对象中

  • getattr(key,default = xxx):获取类或者对象的成员或者属性,如果不存在抛出AttributrError异常,如果

定义了default那么没有属性的时候会返回默认值

  • setattr(key, value):加入有这个属性就更新这个属性,如果没有就添加这个属性并赋值value

  • delattr(key):删除某个属性

    class Test:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        return self.name.self.age 
    obj = Test("yzz",18)
    print(getattr(obj,"name")) #获取属性值
    set(obj,"k1","v1")  #添加属性
    print(hasattr(obj,"k1"))  #查看是否存在这个属性
    delattr(obj,"k1")       #删除这个属性
    

反射和自省能够直接访问以及修改运行的类和对象的成员和属性,实际用例:

import test
addr = input("请输入URL:")
if addr in test.__dict__:
    getattr(test,addr)()
else:
    print("404")

四、单例模式

在面向对象中的单例模式就是一个类只有一个对象,所有的操作都是通过这个对象来完成,示例如下

class Test:
    __v = None
    @classmethod
    def getinstance(cls):
        if cls.__v:
            return cls.__v
        else:
            cls.__v = Test()
            return cls.__v
        
obj1 = Test.getinstance()
obj2 = Test.getinstance()
obj3 = Test.getinstance()
#三个对象的内存地址都是一样的,这样可以节省资源

比如在数据库连接池时使用单例模式,只创建一个类的对象供其他程序调用;Web服务请求中也是使用

这个单例模式