八、类

时间:2019-12-07
本文章向大家介绍八、类,主要包括八、类使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1. 类的分类

类分为新式类经典类(基于Python2.x版本来说的,Python3.x版本中只有新式类。)

1.1 经典类

class Family:
    def __init__(self):
        pass

1.2 新式类

class Family(object):
    pass

1.3 新式类和经典类的区别

# 在Python2中,继承了object的就是新式类,默认的是经典类;
# 在Python3中,都是新式类,默认继承了object(注意:为了程序又更好的向下兼容性,在Python3中定义类时,建议都写成class Family(object)这种格式,而不是class Family这种格式;
# 新式类支持super语法,经典类不支持;
# 在多继承中,新式类采用的是广度优先的查找方法,经典类采用的是深度优先的查找方法;
# 新式类有mro方法,经典类没有mro方法。

2. 类和对象

对象面向对象编程的两个重要元素,在此之前,我们进行编码都是面向过程编程的。对象是类的实例化,一个类可以存在多个对象。

class Family(object):
    pass

obj = Family()

# obj就是Family类的一个对象,上述obj = Family()的过程称为类的实例化。

3. 类的成员

3.1 类的公有成员

class Family(object):

    # 公有属性
    family_name = '赵'

    # 公有绑定方法
    def income(self):
        print(self.family_name + '姓家庭的收支')

    # 公有普通方法
    def pay():
        print('每月固定支出')

# Family类的实例化对象obj
obj = Family()


# 类调用公有属性
print(Family.family_name)

# 类不能调用公有绑定方法
# Family.income()
# TypeError: income() missing 1 required positional argument: 'self'

# 类调用公有普通方法
Family.pay()

# 对象调用公有属性
print(obj.family_name)

# 对象调用公有绑定方法
obj.income()

# 对象不能调用公有普通方法
# obj.pay()
# TypeError: pay() takes 0 positional arguments but 1 was given


# 输出结果
赵
每月固定支出
赵
赵姓家庭的收支

3.2 类的私有成员

# 类的私有成员是以两个连续的下划线'__'开头的字符串命名的,私有成员只能在该类内部使用,其实例化对象和派生类都不能使用。

class Family(object):

    # 私有属性
    __family_money = 1000000

    # 私有方法
    def __save(self):
        print('家庭的储蓄:', self.__family_money)

# 注意:通过_类名__私有成员名的方式可以强行调用类中的私有成员。

4. 类中的方法

4.1 类中的普通方法

# 类中的普通方法是指:在类中定义的没有参数的函数,只有类自身可以调用,对象不能调用。

class Family(object):

    def income():
        print('I am a normal method.')

Family.income()
obj = Family()
obj.income()

# 输出结果
I am a normal method.
Traceback (most recent call last):
  File "E:/python/pycharm/demo/advance/11类中的方法.py", line 12, in <module>
    obj.income()
TypeError: income() takes 0 positional arguments but 1 was given

4.2 类中的静态方法

# 类中的静态方法是指:用staticmethod装饰器修饰的普通方法,类自身和对象都能调用。

class Family(object):

    @staticmethod
    def income():
        print('I am a static method.')

Family.income()
obj = Family()
obj.income()

# 输出结果
I am a static method.
I am a static method.

4.3 类中的绑定方法

  • 绑定到对象
# 类中的绑定到对象的方法是指:在类中定义的第一个参数为self的函数,该方法只能对象调用,类自身不能调用。

class Family(object):

    def income(self):
        print('I am a object method.')

obj = Family()
obj.income()
Family.income()

# 输出结果
I am a object method.
Traceback (most recent call last):
  File "E:/python/pycharm/demo/advance/11类中的方法.py", line 11, in <module>
    Family.income()
TypeError: income() missing 1 required positional argument: 'self'
  • 绑定到类
# 类中的绑定到类的方法是指:在类中定义的第一个参数为cls且用装饰器classmethod修饰的函数,该方法对象和类自身都能调用。

class Family(object):

    @classmethod
    def income(cls):
        print('I am a class method.')

obj = Family()
obj.income()
Family.income()

# 输出结果
I am a class method.
I am a class method.
  • property装饰器
# property装饰器的作用:将类中的方法变为属性,使得在调用时直接按照调用属性的方式调用该方法,并返回该方法的返回值。

class Family(object):

    @property
    def income(self):
        print('I am property.')
        return 12345

obj = Family()
result = obj.income
print(result)

# 输出结果
I am property.
12345

4.4 类中的魔法方法

​ Python中,以两个下划线__开头且以两个下划线__结尾的方法称为魔法方法

  • __new____init____call__

    # __new__魔法方法:用于创建空对象,称为“构造方法”;最先被调用,所有的类都继承了object类,该类中包含了__new__方法,需要重写时在自己的类中重新定义__new__即可。
    # __init__魔法方法:用来对象赋值,称为“初始化方法”,在__new__方法之后被调用。
    # __call__魔法方法:对象后面加括号,会自动调用__call__方法。
    
    class ClassA(object):
    
        def __init__(self):
            print('用于给对象赋值,初始化方法')
    
        def __new__(cls, *args, **kwargs):
            print('用于创建空对象,构造方法')
            return object.__new__(cls)
    
        def __call__(self, *args, **kwargs):
            print('执行call方法')
    
    obj1 = ClassA()
    # 对象后面加括号,会自动调用__call__方法
    obj1()
    
    # 输出结果
    用于创建空对象,构造方法
    用于给对象赋值,初始化方法
    执行call方法
  • __setitem____getitem__delitem__

    class ClassB(object):
    
        def __setitem__(self, key, value):
            # 'k1'传给key, 123传给value
            print(key, value)
    
        def __getitem__(self, item):
            # 'xxx'传给item
            print(item)
    
        def __delitem__(self, key):
            # 'ttt'传给key
            print(key)
    
    obj2 = ClassB()
    obj2['k1'] = 123  # 内部会自动调用 __setitem__方法
    obj2['xxx']  # 内部会自动调用 __getitem__方法
    del obj2['ttt']  # 内部会自动调用 __delitem__方法
    
    # 输出结果
    k1 123
    xxx
    ttt
  • __str__

    class ClassC(object):
    
        def __str__(self):
            '''
            只有在打印对象时,会自动调用此方法,并将其返回值在页面显示出来
            :return: 返回一个字符串
            '''
    
            return 'i can only return a string.'
    
    obj3 = ClassC()
    print(obj3, type(obj3))
    
    # 输出结果
    i can only return a string. <class '__main__.ClassC'>
  • __dict____doc____module__

    class ClassD(object):
        '''用来说明__dict__、__doc__和__module__的作用'''
    
        def __init__(self, name, age, email):
            self.name = name
            self.age = age
            self.email = email
    
    obj4 = ClassD('aaron', 19, '163.com')
    # 去对象中找到所有对象,并转化为字典
    result = obj4.__dict__
    print(result)
    # 得到当前类的说明文档
    result = obj4.__doc__
    print(result)
    # 得到当前操作的区域
    result = obj4.__module__
    print(result)
    
    # 输出结果
    {'name': 'aaron', 'age': 19, 'email': '163.com'}
    用来说明__dict__、__doc__和__module__的作用
    __main__
    • __add____sub____mul__
    class ClassE(object):
    
        def __add__(self, other):
            return '两个对象相加时我被调用了'
    
        def __sub__(self, other):
            return '两个对象相减时我被调用了'
    
        def __mul__(self, other):
            return '两个对象相乘时我被调用了'
    
    obj5 = ClassE()
    obj6 = ClassE()
    result = obj5 + obj6
    print(result)
    result = obj5 - obj6
    print(result)
    result = obj5 * obj6
    print(result)
    
    # 输出结果
    两个对象相加时我被调用了
    两个对象相减时我被调用了
    两个对象相乘时我被调用了

5. 类的继承

5.1 单继承

# 单继承是指:只继承了一个基类(父类)的派生类(子类);基类的公有成员可以由派生类随意调用。

class Father(object):

    def father(self):
        print('I am father.')

# 继承了Father类
class Son(Father):

    def son(self):
        print('I am son.')

obj = Son()
obj.son()
obj.father()

# 输出结果
I am son.
I am father.

5.2 多继承

# 多继承是指:继承了两个及以上的基类的派生类;基类的公有成员可以由派生类随意调用。

class Father(object):

    def father(self):
        print('I am father.')

class Mother(object):

    def mother(self):
        print('I am mother.')

# 继承了Father类和Mother类
class Son(Father, Mother):

    def son(self):
        print('I am son.')

obj = Son()
obj.son()
obj.father()
obj.mother()

# 输出结果
I am son.
I am father.
I am mother.
  • issubclass和isinstance
# issubclass:判断指定类是否为某个类的派生类
# isinstance:判断指定对象是否为某个类的实例话对象

class Grandfather(object):

    def grandfather(self):
        print('I am grandfather.')

class Father(Grandfather):

    def father(self):
        print('I am father.')

class Aunt(object):

    def anut(self):
        print('I am aunt.')

class Son(Father):

    def son(self):
        print('I am son.')

# 判断指定类是否为某个类的派生类
result = issubclass(Son, Father)
print(result)
result = issubclass(Son, Grandfather)
print(result)
result = issubclass(Son, Aunt)
print(result)

obj = Son()
# 判断指定对象是否为某个类的实例话对象
result = isinstance(obj, Son)
print(result)
result = isinstance(obj, Father)
print(result)
result = isinstance(obj, Grandfather)
print(result)
result = isinstance(obj, Aunt)
print(result)

# 输出结果
True
True
False
True
True
True
False
  • super()调用父类方法
# super是一个类;super()是一个对象,用于根据mro列表调用下一个类的绑定方法。
# super的作用:派生类中出现基类中的同名绑定方法时,可以既调用派生类中的方法,又调用基类中的方法。

class Grandfather(object):

    def money(self):
        print("grandfather")

class Father(Grandfather):

    def money(self):
        print("father1")
        super().money()
        print("father2")

class Mother(Grandfather):

    def money(self):
        print("mother1")
        super().money()
        print("mother2")

class Son(Father, Mother):

    def money(self):
        print('son1')
        super().money()
        print('son2')

# 获取使用mro列表
find_list = Son.mro()
print(find_list)

obj = Son()
obj.money()

# 输出结果
[<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class '__main__.Grandfather'>, <class 'object'>]
son1
father1
mother1
grandfather
mother2
father2
son2

# 注意:新式类才支持super和mro方法,mro列表是根据C3算法计算出来的顺序列表,用在多继承中super调用各个类中的同名方法时参照的顺序。
  • 深度优先和广度优先
# 在多继承中,调用类中的同名方法时采用的查找方法分为深度优先和广度优先。
# Python2.x:采用深度优先
# Pyhton3.x:采用广度优先

class Grandfather(object):

    def money(self):
        print("I am grandfather's money.")

class Father(Grandfather):

    pass

class Mother(Grandfather):

    def money(self):
        print("I am mother's money.")

class Son(Father, Mother):

    pass

obj = Son()
obj.money()

# 输出结果
# Python2.x:I am grandfather's money.
# Python3.x:I am mother's money.

5.3 约束

'''
若在基类中有一个定义了一个方法如下所示:
def sex(self):
    raise NotImplementedError()
若存在派生类类继承了该基类,则,派生类中必须定义一个sex方法!
'''

class Father(object):

    def sex(self):
        raise NotImplementedError()

class Son(Father):

    pass

class Daughter(Father):

    def sex(self):
        print('I am a girl.')

obj1 = Daughter()
obj1.sex()
obj2 = Son()
obj2.sex()

# 输出结果
I am a girl.
Traceback (most recent call last):
  File "E:/python/pycharm/demo/advance/13约束.py", line 22, in <module>
    obj2.sex()
  File "E:/python/pycharm/demo/advance/13约束.py", line 7, in sex
    raise NotImplementedError()
NotImplementedError

5.4 反射

根据字符串的形式去某个对象中操作其成员。

  • getattr(对象, "字符串")

    # 根据字符串去指定对象中获取对应和字符串相同名称的成员。
    
    class Father(object):
    
        def __init__(self, money):
            self.money = money
    
        def house(self):
            print(self.money)
    
    obj = Father(12345)
    # 获取属性
    result = getattr(obj, 'money')
    print(result)
    # 获取方法
    result = getattr(obj, 'house')
    result()
    
    # 输出结果
    12345
    12345
  • hasattr(对象, "字符串")

    # 根据字符串判定指定对象中是否有对应和字符串相同名称的成员。
    
    class Father(object):
    
        def __init__(self, money):
            self.money = money
    
        def house(self):
            print(self.money)
    
    obj = Father(12345)
    result = hasattr(obj, 'money')
    print(result)
    result = hasattr(obj, 'house')
    print(result)
    result = hasattr(obj, 'car')
    print(result)
    
    # 输出结果
    True
    True
    False
  • setattr(对象, "变量名", "值")

    # 在指定对象中设置成员。 
    
    class Father(object):
    
        def __init__(self, money):
            self.money = money
    
        def house(self):
            print(self.money)
    
    obj = Father(12345)
    setattr(obj, 'family_name', 'Lions')
    print(obj.family_name)
    
    # 输出结果
    Lions
  • delattr(对象, "字符串")

    # 删除指定对象中对应和字符串相同名称的成员。 
    
    class Father(object):
    
        def __init__(self, money):
            self.money = money
    
        def house(self):
            print(self.money)
    
    obj = Father(12345)
    result = hasattr(obj, 'money')
    print('执行delattr之前', result)
    delattr(obj, 'money')
    result = hasattr(obj, 'money')
    print('执行delattr之后', result)
    
    # 输出结果
    执行delattr之前 True
    执行delattr之后 False

5.5 单例模式

无论实例化多少次,都用第一次创建的那个对象。

  • 格式
class Singleton(object):
    __obj = None

    def __new__(cls, *args, **kwargs):
        if cls.__obj is None:
            cls.__obj = object.__new__(cls)

        return cls.__obj

obj1 = Singleton()
print(obj1)
obj2 = Singleton()
print(obj2)

# 输出结果
<__main__.Singleton object at 0x000001B7952E34E0>
<__main__.Singleton object at 0x000001B7952E34E0>
  • 例子
class Singleton(object):
    __obj = None

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

    def __new__(cls, *args, **kwargs):
        if cls.__obj is None:
            cls.__obj = object.__new__(cls)

        return cls.__obj

obj1 = Singleton('Aaron')
obj2 = Singleton('Joe')
print(obj1.name)
print(obj2.name)

# 输出结果
Joe
Joe

# 注意:obj1和obj2是同一个对象,所以obj1.name和obj2.name是同一个值。

'''
若将上例代码中的:
obj2 = Singleton('Joe')
print(obj1.name)
两行位置互换,则输出结果为:
Aaron
Joe
'''

6. 面向对象三大特征

6.1 封装

对类中成员属性和方法的保护,控制外界对内部成员的访问、修改、删除等操作。

6.2 继承

一个类除了自身所拥有的属性方法之外,还获取了另一个类的成员属性和方法。

6.3 多态

不同的子类对象,调用相同的父类方法,产生不同的执行结果。

原文地址:https://www.cnblogs.com/aaron-zhou/p/12003149.html