Python 基础学习笔记 4 —— 类和对象基础


一、概述

类和对象是面向对象编程的一道坎,只要搞理解清楚这几个概念,就会轻松许多。

以下内容都是我自己的理解,仅供参考。

(class) 是一个抽象的概念,指的是具有某种特性的事物的集合。

对象 (object) 是类里面的个体,是类的实例化

方法体就是类里面的函数

在 Python 中,一切皆对象!

例如,一个整形变量是 int 类中的一个对象。


二、类的创建和实例化

用法举例

创建一个名为 lei_2 的空类,然后实例化它。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_2():  #创建一个名为 lei_2 的空类
    pass

a=lei_2()       #实例化类 lei_2

a

运行结果:

<__main__.lei_2 object at 0x102a7f2e8>

可以看出,a 就是 lei_2 中的对象。


三、方法的构建与调用

用法举例 1

创建一个名为 lei_3_1 的类,在里面构建一个名为 fanfa_3_1 的方法体,然后调用它。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_3_1():  #创建一个名为 lei_3_1 的类
    def fanfa_3_1(self):             #无论方法体是否需要传递参数,都必须要有self这个形参
       print('方法体 "fanfa_3_1" 已经被调用。')

a=lei_3_1()       #实例化类 lei_3_1

a.fanfa_3_1()     #调用类 lei_3_1 中的方法体 fanfa_3_1

#也可以写成 lei_3_1().fanfa_3_1()

运行结果:

方法体 "fanfa_3_1" 已经被调用。

用法举例 2

创建一个名为 lei_3_2 的类,在里面构建一个方法体,当这个类被实例化时,自动调用它。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_3_2():  #创建一个名为 lei_3_2 的类
    def __init__(self):             #如果方法体需要在类实例化的时候自动调用,就应该把它命名为 __init__
    #如果未指定调用的方法体,默认调用 __init__
       print('方法体 "__init__" 已经被调用。')

a=lei_3_2()       #实例化类 lei_3_2
#这里我们没有调用方法体

运行结果:

方法体 "__init__" 已经被调用。

四、向方法体中传递参数

用法举例

创建一个名为 lei_4 的类,在里面构建一个名为 fanfa_4 的方法体,然后再调用它的同时向类中传递参数。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_4():  #创建一个名为 lei_4 的类
    def fanfa_4(self,arg1,arg2):             #无论函数是否需要传递参数,都必须要有self这个形参
       print('方法体 "fanfa_4" 已经被调用。')
       print('变量 "arg1" 是:{} ,变量 "arg2" 是:{} 。'.format(arg1,arg2))
#请注意,变量 arg1 和 arg2 的作用域只在方法体 fanfa_4 内

a=lei_4()       #实例化类 lei_4

a.fanfa_4('aaa',111)     #调用类 lei_4 中的方法体 fanfa_4,并传递参数

运行结果:

方法体 "fanfa_4" 已经被调用。
变量 "arg1" 是:aaa ,变量 "arg2" 是:111 。

五、方法体变量、实例变量和类变量

用法举例 1

在上节程序的基础上,把方法体内的变量转换为实例变量,然后新建一个实例变量。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_5_1():
    def fanfa_5_1(self,arg1,arg2):
       print('*****方法体 "fanfa_5_1"*****')
       print('方法体变量 "arg1" 是:{} ,方法体变量 "arg2" 是:{} 。\n'.format(arg1,arg2))
       #把两个方法体变量转换为实例变量
       self.arg1=arg1
       self.arg2=arg2

    def fanfa_5_2(self):
       print('*****方法体 "fanfa_5_2"*****')
       self.arg3 = 'bbb'    #定义实例变量
       print('实例变量 "arg1" 是:{} ,实例变量 "arg2" 是:{} ,实例变量 "arg3" 是:{}。\n'.format(self.arg1,self.arg2,self.arg3))
    #在此程序中,实例变量的调用要加上 self. 这个前缀

# arg1 、arg2 和 arg3 的作用域都是整个类中的一个实例,不同实例互不影响

a=lei_5_1()

a.fanfa_5_1('aaa',111)

a.fanfa_5_2()

运行结果:

*****方法体 "fanfa_5_1"*****
方法体变量 "arg1" 是:aaa ,方法体变量 "arg2" 是:111 。

*****方法体 "fanfa_5_2"*****
实例变量 "arg1" 是:aaa ,实例变量 "arg2" 是:111 ,实例变量 "arg3" 是:bbb。

用法举例 2

创建一个名为 lei_5_2 的类,内含一个类变量 var_1 和一个实例变量 var_2,在第一个实例中改变它们的值,看看能否在第二个实例中生效(请注意区分类变量和实例变量的调用格式)。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_5_2:

    var_1 = 'aaa'                   #初始化类变量

    def __init__(self):
        self.var_2 = 'xxx'          #初始化实例变量

    def gaibian_lei_var(self,a):    #修改类变量
        lei_5_2.var_1=a
        print("类变量的值已更改!")

    def print_lei_var(self):        #打印类变量
        print("类变量的值为:{}".format(lei_5_2.var_1))    #类变量的调用格式:<类名>.<变量名>

    def gaibian_shili_var(self,b):  #修改实例变量
        self.var_2=b
        print("实例变量的值已更改!")

    def print_shili_var(self):  #打印类变量
        print("实例变量的值为:{}".format(self.var_2))  #实例变量的调用格式:self.<变量名>

a=lei_5_2() #第一次实例化
print("*****这是第一个实例*****")
a.print_lei_var()
a.print_shili_var()
a.gaibian_lei_var('bbb')    #改变类变量的值
a.gaibian_shili_var('yyy')
a.print_lei_var()
a.print_shili_var()

b=lei_5_2() #第二次实例化
print("\n*****这是第二个实例*****")
b.print_lei_var()
b.print_shili_var()

运行结果:

*****这是第一个实例*****
类变量的值为:aaa
实例变量的值为:xxx
类变量的值已更改!
实例变量的值已更改!
类变量的值为:bbb
实例变量的值为:yyy

*****这是第二个实例*****
类变量的值为:bbb
实例变量的值为:xxx

总结

方法体变量的作用域在类的一个实例中的一个方法体内。

实例变量的作用域在类的一个实例中。

类变量的作用域在类的所有实例中。


六、静态方法体 & 类方法体

以下只做简单说明,因为自己还没弄清楚实际用途。

用法举例

创建一个名为 lei_6 的类,在里面构建一个名为 jintai_fanfa_6 的静态方法体和一个名为 lei_fanfa_6 的类方法体,然后不进行实例化直接调用它们。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_6():
    @staticmethod   #静态方法体修饰语句
    def jintai_fanfa_6():   #静态方法体可以不指定形参
        print("这里是静态方法体!")

    @classmethod    #类方法体修饰语句
    def lei_fanfa_6(cls):   #无论方法体是否需要传递参数,都必须要有cls这个形参
        print("这里是类方法体!")   

lei_6.jintai_fanfa_6()  #免实例化调用静态方法体
lei_6.lei_fanfa_6() #免实例化调用类方法体

#要写成 lei_6().jintai_fanfa_6() 这种形式才有经过实例化,请注意区分!

运行结果:

这里是静态方法体!
这里是类方法体!

七、类的继承

用法举例

分别创建两个父类、两个子类。第一个子类继承一个父类,第二个子类继承两个父类,然后改写父类中的方法体、增加子类方法体。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class lei_7_1():    #定义父类 lei_7_1
    def __init__(self):
        print('*****这里是父类 lei_7_1*****')
    def fangfa(self):
        print('这里调用的是 lei_7_1 中的方法体 fangfa\n')

class lei_7_2():    #定义父类 lei_7_2
    def __init__(self):
        print('*****这里是父类 lei_7_2*****')
    def fangfa(self):
        print('这里调用的是 lei_7_2 中的方法体 fangfa\n')

class sub_7_1(lei_7_1): #定义子类 sub_7_1
    def __init__(self): #改写父类方法体
        print('*****这里是子类 sub_7_1*****')
        print('我继承了父类 lei_7_1')
    def fangfa_new(self):   #定义新方法体
        print('这是我的新方法体 fangfa_new')

class sub_7_2(lei_7_1,lei_7_2): #定义子类 sub_7_2
    def __init__(self): #改写父类方法体 __init__
        print('*****这里是子类 sub_7_2*****')
        print('我先继承了父类 lei_7_1 ,再继承了父类 lei_7_2')

class sub_7_3(lei_7_2,lei_7_1): #定义子类 sub_7_3
    def __init__(self): #改写父类方法体 __init__
        print('*****这里是子类 sub_7_3*****')
        print('我先继承了父类 lei_7_2 ,再继承了父类 lei_7_1')

a=sub_7_1() 
a.fangfa_new()  #调用子类中的新方法体
a.fangfa()  #调用父类的方法体

b=sub_7_2()
b.fangfa()  #调用父类的方法体

c=sub_7_3()
c.fangfa()  #调用父类的方法体

运行结果:

*****这里是子类 sub_7_1*****
我继承了父类 lei_7_1
这是我的新方法体 fangfa_new
这里调用的是 lei_7_1 中的方法体 fangfa

*****这里是子类 sub_7_2*****
我先继承了父类 lei_7_1 ,再继承了父类 lei_7_2
这里调用的是 lei_7_1 中的方法体 fangfa

*****这里是子类 sub_7_3*****
我先继承了父类 lei_7_2 ,再继承了父类 lei_7_1
这里调用的是 lei_7_2 中的方法体 fangfa

总结

Python 支持单重和多重继承。

使用单重继承时,子类将父类中的方法体完全继承过来。如果发现有和父类重名的方法体,则会覆盖父类中的方法体。

使用多重继承时,继承顺序十分重要。如果两个父类中有同名的方法体,则优先继承第一个父类中的方法体。

发表评论