Python面向对象-类和实例

面向对象技术简介

类(class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

实例化:创建一个类的实例,类的具体对象。

类方法:类中定义的函数。

类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

创建类

在Python中,定义类是通过class关键字:

class Student([extendClass]):
    pass

class后面紧接着是类名,类名通常时大写字母开头,如果该类是从某个其他类继承下来的,类名后面需要跟上继承自哪个类。

创建一个实例

根据Student类,创建一个Student的实例:

stu1 = Student()

可以看出,stu1就是Student类的一个实例化对象:

image-20211011121609008

可以自由地给一个实例变量绑定属性,比如,给实例stu1绑定一个sname属性:

image-20211011121851836

由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把snamescore等属性绑上去:

class Student:
    def __init__(self, sname, sorce):
        self.sname = sname
        self.sorce = sorce

📓注意:特殊方法__init__前后分别有两个下划线。

__init__方法的第一个参数永远是self ,表示创建的实例本身。因此,在方法内部就可以把各种属性绑定到self,因为self就指向创建的实例本身。

有了__init方法,在创建实例的时候就需要传入和__init__方法相匹配的参数。其中self参数不需要传递,Python会自己把实例的对象传给self

image-20211011133308283

和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

数据封装

面向对象编程的一个重要特点就是数据封装。在上面的Student类中,每个实例就拥有各自的namescore这些数据。我们可以通过函数来访问这些数据,比如打印一个学生的成绩。

在类的内部定义一个访问数据的函数,这些函数称为:类的方法。

class Student:
    def __init__(self, sname, score):
        self.sname = sname
        self.score = score

    def print_score(self):
        print(f"{self.sname}的成绩为:{self.score}")

要定义一个类的方法,除了第一个参数是self外,其他和普通函数一样。

那么如何调用一个类的方法呢?只需要在实例变量上直接调用,传入除self 之外的其他参数:

stu2 = Student("李四", 99)
stu2.print_score()

image-20211011134649819

这样一来,我们从外部看Student类,就只需要知道,创建实例需要给出namescore,而如何打印,都是在Student类的内部定义的,这些数据和逻辑被“封装”起来了,调用很容易,但却不用知道内部实现的细节。

封装的另一个好处是可以给Student类增加新的方法,比如get_grade

class Student(object):
    ...

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
小结

类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;

方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;

通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。

访问限制

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的namescore属性:

stu1 = Student("张三", 80)
stu1.print_score()
stu1.score = 90
stu1.print_score()

image-20211011135802236

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

class Student:
    def __init__(self, sname, score):
        self.__sname = sname
        self.__score = score

    def print_score(self):
        print(f"{self.__sname}的成绩为:{self.__score}")

改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name实例变量.__score了:

image-20211011140145743

这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

但是如果外部代码要获取name和score怎么办?可以给Student类增加get_nameget_score这样的方法:

class Student(object):
    ...
    
    def get_name(self):
        return self.__name
    
    def get_score(self):
        return self.__score

image-20211011140931997

如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:

class Student(object):
    ...

    def set_score(self, score):
        self.__score = score

image-20211011141134641

这样做还有一个好处,就是可以对参数进行检查,避免传入无效的参数:

    def set_score(self, score):
        if score < 0 or score > 100:
            print("参数无效")
        else:
            self.__score = score

image-20211011141453014

注意下面这种错误写法:

image-20211011142105317

表面上看来,“成功”地设置了__sname变量,但实际上这个__sname和class内部的__sname并不是同一个变量,上面的代码只是给实例stu1新增了一个属性,命名为__sname,而内部的私有变量__sname已经被Python解释器自动更改成了其他的名字。

posted @ 2021-10-11 14:31  雨-铃  阅读(361)  评论(0编辑  收藏  举报
Tips
复制成功!