刘刚刚的个人博客

python基础-类与对象(元类未补充完)

创建时间:2020-08-28 16:12:02
更新时间:2020-08-28 16:12:02

类也是对象

面向过程:将复杂的流程化,进而简单化

面向对象:提升程序的解耦合程序,进而提高程序的可扩展性

类与对象

简单定义:

# 命名推荐采用大驼峰
class MyClass:
    
    name = null
    
    # 类的初始化方法,可以省略,self代表实例化的对象。返回值必须为None,或没有返回值
    def __init__(self,param):
        self.name = param
     
    # 方法
    def fun(self):
        print(name)

# 查看类的属性和方法
print(MyClass.__dict__)

# 实例化
obj = MyClass('shuta')

# 使用对象的方法,在调用时会默认将对象本身作为第一个参数传递到方法中
obj.fun()

# 使用类调用方法,比如按照定义时的参数进行传递
MyClass(obj)

在类中除了属性和函数之外,也可以有能直接执行的语句,这些语句会在类定义时直接执行,如:print(),但不建议这么写。

隐藏属性

通过双下划线可以将变量或者方法定义为隐藏属性或方法,在python中隐藏属性是通过改变属性或函数的名字来实现的。

通过隐藏属性,可以隐藏内部的实现

class MyClass:
    __name__ = 'shuta'
    
    def __format__(self):
        return '名字:'+self.__name__
        
    def get_info(self):
        return self.__format__

property

使用property可以用来装饰类中的方法,让访问方法和访问类一样

# 使用方式1:装饰方法为属性
class MyClass:
    
    @property
    def test():
        return 'test'

obj = MyClass()
# 原来访问时,需要加括号,现在可以当作属性来访问
obj.test

# 使用方式2:修改属性的访问方式
class MyClass:
    
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        print('获取了name')
        return self.__name
    
    def set_name(self,name):
        print('修改了name')
        self.__name = name
    
    def del_name(self,name):
        print('删除了name')
        del  self.__name
    
    # 定义对name属性的操作,执行相应的方法,方法顺序,读-设置-删除
    name = property(get_name,set_name,del_name)    
        
obj = MyClass('shuta')
# 调用属性时,调用的为方法
obj.name
obj.name = 'shuta1'
del obj.name

# 方式2的另外一中写法
class MyClass:
    
    def __init__(self,name):
        self.__name = name

    # 定义需要使用属性访问的方法
    @property
    def name(self):
        print('获取了name')
        return self.__name
    # 定义设置时触发的方法
    @name.setter
    def set_name(self,name):
        print('修改了name')
        self.__name = name
        
    # 定义删除时触发的方法
    @name.deleter
    def del_name(self,name):
        print('删除了name')
        del  self.__name
        
        
obj = MyClass('shuta')
obj.name
obj.name = 'shuta1'
del obj.name

继承

python支持多继承.多继承的优缺点:

  • 可以最大限度的重用代码
  • 会让可读性变差,逻辑分析会比较麻烦,进而扩展性变差

在python3中所有的类默认都继承object 基类,

在python2中,同时存在经典类和新式类,经典类不继承object对象,如果有经典类继承了object那么他及子类都为新式类

菱形继承及非菱形继承

继承的几个类的基类为同一个则为菱形继承(除object为基类的情况),在菱形继承中,会从左到右的分支依次寻找属性或函数,但最后才会查找共同的头部类中的属性或函数(广度优先)。

非菱形继承从左到右的分子依次寻找(深度优先)

# 查看类的父类,只能看到一个
类.__base__

# 查看属性或者功能的查找顺序    ,只对新式类生效
类.mro()

mixins

mixins不是语法,而是规范.

通过mixins机制可以提升多继承下的可读性,对为类添加功能的类增加mixin后缀,与其他类进行区分

class A:
    pass

class BMixin:
    pass

class C(A,BMixin):
    pass

子类派生方法中调用父类中的功能

方式一:在使用父类进行调用

class A:
    def __init__(self):
        pass

class B(A):
    def __init__(self):
        # 通过类嗲用,并传入当前对象
        A.__init__(self)

方式二:使用super

使用super()会得到一个特殊的对象,该对象会参照当前类的MRO依次去寻找属性或方法

class A:
    def __init__(self):
        pass

class B(A):
    def __init__(self):
        # 通过类嗲用,并传入当前对象
        super(A,self).__init__() # python2中的写法
        super().__inti__() # python3可以这么写

mro 查找示例:

class A:
    def test(self):
        # 本案例中,此处的super()指向的为B类
        super().test()
    
class B:
    def test(self):
        pass

class C(A,B):
    pass
ob = C()
ob.test() # 查找顺序:A->B ,在A中遇到super(),根据C的MRO,A中执行super()后会去B中寻找

多态

多态指对象拥有相同的功能,但功能又不完全一样.

# 这是一个使用继承实现多态的方法
class A:
    def get(self):
        pass
    
class B(A):
    def get(self):
        pass
    
class C(A):
    def get(self):
        pass

def test(A)
    return A.get()

b = B()
c = C()

test(b)
test(c)

鸭子类型

当某些类都有一个功能且又有差别时,python中约定对这些类写统一的方法进行调用,无需继承.即鸭子类型

通过鸭子类型,可以降低程序的耦合度

# 直接调用
b = B()
b.get()

tip:

python中支持使用抽象类来约束子类的功能,但更推崇鸭子类型

# 使用抽象
import abc
# 设置为抽象类
class A(metaclass=abc.ABCMeta):
 @abc.abstractmethod # 限制子类需要实现的方法
 def test(self): # 抽象方法中无需实现具体的功能
     pass

class B(A): 
 # 子类必须实现,父类中的抽象方法,否则会抛出TypeError异常
 def test(self):
     pass

b = B() #

绑定方法-classmethos

包括两种:

  1. 绑定给对象的.(在使用对象调用时,自动传入对象)
  2. 绑定给类的(调用时,自动传入类)

经常用在通过读取参数生成对象的场景

class A:
    
    @classmethods  # 通过装饰器声明传进去的为类名
    def get_obj(cls):
        return cls()

a = A.get_obj()

非绑定方法(静态方法) -staticmethod

当一个函数不需要传入类也不需要传入对象时可以使用静态方法

class A:
    
    @staticmethod
    def test():
        return 1

A.test()

反射

反射指在程序动态执行的过程中获取对象的信息

反射可以通过dir,__dict__实现

python提供了通过字符串操作属性值的方式

# 判断是否有某个属性
hasattr(对象,'属性名')

# 获取属性值
getattr(对象,'属性名')

# 设置属性值
setattr(对象,'属性名',值)

# 删除属性
delattr(对象,'属性名')

内置方法

  1. 打印时自动触发 __str__
  2. 删除对象时触发 __del__ ,一般用于回收系统资源

    class A:
        def __str__(self):
            return 'A'
       
        def __del__(self):
            pass
    a = A()
    print(a) #调用__str__
    del a  # 调用del
    tip:

    在程序运行结束,回收内存的时候也会先执行__del__

元类

其他类都是通过元类创建出来的。对象是类的实例化,类是对象的实例化。

创建类时,即为调用type的实例化过程__call__():

  1. 执行要__new__()创建出类的空对象,如果要创建中的类不存在__new__(),则会寻找到type中(因为类为元类的实现)
  2. 执行__init()__对数据进行初始化,
  3. 返回创建好的类
tip:创建类时的__call__与对象调用时的__call__的区别

type与object的关系

object是type类的实现

type继承object

在python中的源码中,会预先初始化type与object的内存,此时都处于不可使用的状态,然后在初始化时,建立他们之间的关系,此时就可以调用了

class机制的四个步骤

元类中的 new call init 及对象中的分析

类和对象下的属性查找步骤

如果调用普通对象的属性,则查找顺序为:

对象本身 -> 父类 -> object类 (不会去查找type类,因为对象的基类为object,非type)

如果直接调用类的属性,则查找顺序为:

类本身 -> 自定义原类 -> type

我的名片

昵称:shuta

职业:后台开发(python、php)

邮箱:648949076@qq.com

站点信息

建站时间: 2020/2/19
网站程序: ANTD PRO VUE + TP6.0
晋ICP备18007778号