美文网首页
Python学习(九)--面向对象、构造函数

Python学习(九)--面向对象、构造函数

作者: 白面葫芦娃92 | 来源:发表于2020-03-20 21:58 被阅读0次
    命名规则Tips:
    (1)变量全部用小写,单词间用下划线连接,如student_age
    (2)类名单词首字母大写,单词间不建议用下划线连接,用驼峰式命名,即每个单词首字母大写,如StudentHomework

    1.如何构建一个类

    (1)类是现实世界或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起
    (2)类最基本的作用:封装变量和函数
    (3)类是为了定义和描述类的行为和特征,类的设计是一门艺术,最重要的是找到类的行为和特征,不要在类内部调用定义的函数
    (4)一个模块下,不要既定义类,又实例化类,要么全都是实例化,要么全都写类
    (5)类就像一个模板,通过类,可以生成很多个对象
    class Student():
        name = ''
        age = 18
    
        def print_info(self):
            print('name:' + self.name)
            print('age:' + str(self.age))
    
    a.类里的方法()中必须有self
    b.方法中变量的引用,前边也必须加self.

    不然都会报错

    2.类实例化

    从另一个模块引用上面定义的类

    from t import Student
    student = Student()
    #与其他语言不同,不需要new
    #调用类中的方法:
    student.print_info()
    

    返回结果

    name:
    age:18
    

    3.方法和函数的区别

    方法:面向对象层面、设计层面
    函数:面向过程层面,是程序运行、过程式的一个称谓
    类内部的函数,称作方法比较合适
    模块下的函数,称作函数比较合适;
    类内部的变量,称作数据成员比较合适
    模块下的变量,称作变量比较合适

    4.构造函数

    (1)认识构造函数

    class Student:
        def __init__(self):
            print('student')
    

    实例化时,构造函数会隐式地自动调用,因此一般不会显式调用构造函数
    当显式调用时,构造函数会返回什么值呢?

        student1 = Student()
        a = student1.__init__()
        print(a)
        print(type(a))
    

    返回结果

    student
    student
    None
    <class 'NoneType'>
    

    从结果可以看出,student打印出了两次,说明第1行实例化时,__init__()函数已经被调用了一次;
    第2行显式调用,__init__()函数又被调用了一次;
    __init__()返回值为None
    那么可以强制__init__()函数返回其他结果吗?我们来试验一下,让__init__()函数强制返回一个字符串:

        def __init__(self):
            print('student')
            return 'student'
    

    运行结果,报错:

    student
    Traceback (most recent call last):
      File "c1.py", line 61, in <module>
        student1 = Student()
    TypeError: __init__() should return None, not 'str'
    

    错误提示,__init__()函数只能返回None,不能返回其他类型的值
    (2)构造函数的作用:以类为模板生成不同的对象
    将构造函数改为:

        def __init__(self, name, age):
            name = name
            age = age
    
    if __name__ == "__main__":
        student1 = Student()
    

    运行报错:

    Traceback (most recent call last):
      File "c1.py", line 62, in <module>
        student1 = Student()
    TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
    

    构造函数中需要括号内输入name和age两个参数,在实例化时也必须输入
    那么入两个值之后,看一下输入的值有没有生效

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name, age):
            name = name
            age = age
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(student1.age)
    

    返回结果:

    0
    

    说明输入的参数并没有改变类下面定义的变量的值

    5.类变量和实例变量

    要想理解上面的现象为什么出现,首先需要理解以下两个概念:
    类变量:和类相关的变量
    实例变量:和对象相关的变量

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(student1.age)
        print(Student.age)
    

    第2/3行中的name和age是类变量
    第5/6行中的name和age是实例变量

    这是和其他语言很重要的不同之处,要注意!

    运行结果:

    18
    0
    

    运行结果说明,类Student的类变量age和实例student1的实例变量age是不同的,它们两个没有关系
    也就是说,第4章中的例子本想打印实例变量,却打印出了类变量
    通过__dict__变量(python自带的可以看到类或者对象下所有变量的字典)来看一下

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name, age):
            name = name
            age = age
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(student1.__dict__)
    

    返回结果:

    {}
    

    说明对象student1下没有任何变量,也就是说print(student1.age)打印了一个不存在的变量,为什么打印的不是none呢?
    这就涉及python的一个内部机制,当要打印某个实例变量时,首先在实例变量里找,如果找不到,就会在类变量里找同名的类变量,如果类变量里还是找不到,接下来会在父类里继续找。所以print(student1.age)打印出了类变量age的值
    做下修改后

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(student1.__dict__)
    

    运行结果

    {'name': '小明', 'age': 18}
    

    这时对象student1下有了name和age两个变量。

    注意:self只和对象有关,实例化了对象1,self就指代1,实例化了2,self就指代对象2,self在实例方法(构造函数是一种特殊的实例方法,和普通的实例方法区别在于1.调用方法不同2.意义不同:构造函数意义在于初始化,普通的实例方法在于操作实例变量)里必须显式出现。
    看到上面的例子不禁思考,创建一个类时,直接给类变量赋值有什么意义呢?name和age是描述student这类人的属性的,而这个属性却有具体的值岂不是很奇怪的事情?????

    所以说上面对于类变量的用法不合适,通常类变量可以这么用,比如统计基于该类实例化的实例的数量:

    class Student():
        sum = 0
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
            self.__class__.sum += 1
            print('当前班级学生总数为:' + str(self.__class__.sum))
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        student2 = Student('小红',17)
        student3 = Student('小鱼',19)
        student4 = Student('小鹿',20)
        student5 = Student('小凯',17)
    

    运行结果

    当前班级学生总数为:1
    当前班级学生总数为:2
    当前班级学生总数为:3
    当前班级学生总数为:4
    当前班级学生总数为:5
    

    上述类变量累加不仅是可以在构造函数里执行,放在任意一个实例方法里都可以执行

    6.变量的作用域(类内的变量和模块内的变量所遵循的规则不同,不要把它们作类比)。也就是说,上面提到的问题,不要用本章的全局变量和局部变量做类比进行记忆

    c = 50
    
    def add(x, y):
        c = x + y
        print(c)
    
    add(1,2)
    print(c)
    

    运行结果:

    3
    50
    

    第一行的c是全局变量
    第4行的c是在函数内的局部变量,其虽与第1行的全局变量同名,但通过运行结果可以看出,局部变量的值不能够覆盖全局变量

    7.总结

    变量用来刻画类的特征
    方法用来描述类的行为
    实例方法操作实例变量(注意self)
    下面看一个例子印证一下:

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
            print(self.name)
            print(name)
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
    

    运行结果:

    小明
    小明
    

    第7行的self.name很好理解,打印的是实例变量
    第8行的name打印的是哪个变量呢?难道name前不加self.也可以?都代表的是实例变量?
    修改一下代码测试一下:

    class Student():
        name = ''
        age = 0
    
        def __init__(self, name1, age):
            self.name = name1
            self.age = age
            print(self.name)
            print(name)
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
    

    运行结果

    小明
    Traceback (most recent call last):
      File "c1.py", line 64, in <module>
        student1 = Student('小明',18)
      File "c1.py", line 56, in __init__
        print(name)
    NameError: name 'name' is not defined
    

    第一个self.name正常打印出来了,但是打印第二个name的时候报错name 'name' is not defined,说明上一个例子print(name)打印的不是实例变量,而是形参name,形参名称一改动,就找不到name这个变量了
    因此,在实例方法内部,想访问实例变量,前边一定要加self.

    实例方法内部,如何访问类变量呢?
    class Student():
        gender = ''
        name = ''
        age = 0
    
        def __init__(self, name1, age):
            self.name = name1
            self.age = age
            print(gender)
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
    

    运行结果

    Traceback (most recent call last):
      File "c1.py", line 65, in <module>
        student1 = Student('小明',18)
      File "c1.py", line 57, in __init__
        print(gender)
    NameError: name 'gender' is not defined
    

    报错,说明在实例方法内部,直接访问类变量不可行
    方法1:之前说过,在外部,可以直接访问类变量,那么在内部也可以用这种方法

    class Student():
        gender = 'male'
        name = ''
        age = 0
    
        def __init__(self, name1, age):
            self.name = name1
            self.age = age
            print(Student.gender)
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(Student.age)
    

    运行结果

    male
    0
    

    方法2:利用self.__class__

    class Student():
        gender = 'male'
        name = 'xiaoming'
        age = 0
    
        def __init__(self, name1, age):
            self.name = name1
            self.age = age
            print(Student.gender)
            print(self.__class__.name)
    
    if __name__ == "__main__":
        student1 = Student('小明',18)
        print(Student.age)
    

    运行结果

    male
    xiaoming
    0
    

    相关文章

      网友评论

          本文标题:Python学习(九)--面向对象、构造函数

          本文链接:https://www.haomeiwen.com/subject/fiflyhtx.html