Python面向对象-类和实例
面向对象技术简介
类(class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
实例化:创建一个类的实例,类的具体对象。
类方法:类中定义的函数。
类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
创建类
在Python中,定义类是通过class
关键字:
class Student([extendClass]):
pass
class
后面紧接着是类名,类名通常时大写字母开头,如果该类是从某个其他类继承下来的,类名后面需要跟上继承自哪个类。
创建一个实例
根据Student
类,创建一个Student
的实例:
stu1 = Student()
可以看出,stu1
就是Student
类的一个实例化对象:
可以自由地给一个实例变量绑定属性,比如,给实例stu1
绑定一个sname
属性:
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__
方法,在创建实例的时候,就把sname
,score
等属性绑上去:
class Student:
def __init__(self, sname, sorce):
self.sname = sname
self.sorce = sorce
📓注意:特殊方法__init__
前后分别有两个下划线。
__init__
方法的第一个参数永远是self
,表示创建的实例本身。因此,在方法内部就可以把各种属性绑定到self
,因为self
就指向创建的实例本身。
有了__init
方法,在创建实例的时候就需要传入和__init__
方法相匹配的参数。其中self
参数不需要传递,Python会自己把实例的对象传给self
。
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self
,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
数据封装
面向对象编程的一个重要特点就是数据封装。在上面的Student
类中,每个实例就拥有各自的name
和score
这些数据。我们可以通过函数来访问这些数据,比如打印一个学生的成绩。
在类的内部定义一个访问数据的函数,这些函数称为:类的方法。
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()
这样一来,我们从外部看Student
类,就只需要知道,创建实例需要给出name
和score
,而如何打印,都是在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类的定义来看,外部代码还是可以自由地修改一个实例的name
、score
属性:
stu1 = Student("张三", 80)
stu1.print_score()
stu1.score = 90
stu1.print_score()
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在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
了:
这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。
但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name
和get_score
这样的方法:
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score
方法:
class Student(object):
...
def set_score(self, score):
self.__score = score
这样做还有一个好处,就是可以对参数进行检查,避免传入无效的参数:
def set_score(self, score):
if score < 0 or score > 100:
print("参数无效")
else:
self.__score = score
注意下面这种错误写法:
表面上看来,“成功”地设置了__sname
变量,但实际上这个__sname
和class内部的__sname
并不是同一个变量,上面的代码只是给实例stu1
新增了一个属性,命名为__sname
,而内部的私有变量__sname
已经被Python解释器自动更改成了其他的名字。
本文来自博客园,作者:雨-铃,原文链接:https://www.cnblogs.com/yuling25/p/oop_class.html