> 文章列表 > Python基础之类

Python基础之类

Python基础之类

一:什么是类

类即类别/种类,是面向对象分析和设计的基石,如果多个对象有相似的数据与功能,那么该多个对象就属于同一种类。有了类的好处是:我们可以把同一类对象相同的数据与功能存放到类里,而无需每个对象都重复存一份,这样每个对象里只需存自己独有的数据即可,极大地节省了空间。所以,如果说对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器。

 类:可以理解成一个模板

实例:根据模版创建出来的一个对象

属性:这类东西具有的特征,例如:汽车的重量,品牌

方法:这类东西可以做的事情,例如:汽车可以刹车

必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)

二、类的定义与实例化

使用关键字class定义类

将共有属性提取到:init初始化函数中

定义共有的方法

class Student:school = '华阳中学'def __init__(self, name, age, sex):self.name = nameself.age = ageself.sex = sexdef choose(self):print(f'{self.name} is choosing a course')

调用类的过程就是类的实例化,拿到的返回值就是程序中的一个对象,或称为一个实例

stu1 = Student("json", 20, "男")   # 每实例化一次Student类就得到一个学生对象
stu2 = Student("lili", 21, "女")
stu3 = Student("jack", 19, "男")

单拿stu1的产生过程来分析,调用类会先产生一个空对象stu1,然后将stu1连同调用类时括号内的参数一起传给Student.__init__(stu1,"json", 20, "男")

def __init__(self, name, age, sex):self.name = name  # stu1.name = 'json'self.age = age    # stu1.age = 20self.sex = sex    # stu1.sex = '男'

会产生对象的名称空间,同样可以用__dict__查看

print(stu1.__dict__)
# {'name': 'json', 'age': 20, 'sex': '男'}

我们造出了三个对象(实例)与一个类,对象(实例)存放各自独有的数据,类中存放对象(实例)们共有的内容。

三、访问属性

3.1:类属性与实例属性

在类中定义的名字,都是类的属性,分为两种:数据属性和函数属性。可以通过__dict__访问属性的值,比如Student.__dict__[‘school’],但Python提供了专门的属性访问语法。

print(Student.school)   # 访问数据属性,等同于Student.__dict__[‘school’]
# 华阳中学
print(Student.choose)   # 访问函数属性,等同于Student.__dict__[‘choose’]
# <function Student.choose at 0x100588940>

操作对象属性也是一样的

print(stu1.name)   # 查看,等同于stu1.__dict__[‘name’]
# json
stu1.course = '语文'    # 新增,为stu1新增course属性,等同于stu1.__dict__[‘course’] = '语文'
print(stu1.course)  # 语文
stu1.age = 22      # 修改,修改stu1的age属性,等同于stu1.__dict__[‘age’] = 22
print(stu1.age)    # 22
del stu1.course    # 删除,删除stu1的course属性
print(stu1.course)  # 抛异常:AttributeError: 'Student' object has no attribute 'course'

当类的数据属性为不可变类型(字符串、数字、元组)时,通过修改实例对象的数据属性的值,不会修改类的数据属性的值,也不会修改其他实例对象属性的值;通过类去修改数据属性的值,会改变所有实例对象的属性的值;

当类的数据属性为可变类型(列表、字典、集合)时,修改实例对象的数据属性的值,会修改类的数据属性的值,同时也会修改其他实例对象属性的值;通过类去修改数据属性的值,会改变所有实例对象的属性的值;

class Student:school = '华阳中学'course = []def __init__(self, name, age, sex):self.name = nameself.age = ageself.sex = sexdef choose(self):print(f'{self.name} is choosing a course')stu1 = Student("json", 20, "男")   # 每实例化一次Student类就得到一个学生对象
stu2 = Student("lili", 21, "女")

修改实例对象中不可变的类属性:

print(Student.school)    # 华阳中学
print(stu1.school)       # 华阳中学
print(stu2.school)       # 华阳中学
stu1.school = '成都七中'
print(Student.school)    # 华阳中学
print(stu1.school)       # 成都七中
print(stu2.school)       # 华阳中学

通过类修改不可变的类属性:

print(Student.school)     # 华阳中学
print(stu1.school)        # 华阳中学
print(stu2.school)        # 华阳中学
Student.school = '成都七中'
print(Student.school)     # 成都七中
print(stu1.school)        # 成都七中
print(stu2.school)        # 成都七中

修改实例变量中可变类型的值:

print(Student.course)      # ['语文']
print(stu1.course)         # ['语文']
print(stu2.course)         # ['语文']
stu1.course.append('数学')
print(Student.course)      # ['语文', '数学']
print(stu1.course)         # ['语文', '数学']
print(stu2.course)         # ['语文', '数学']

通过类修改可变类型的类属性:

print(Student.course)      # ['语文']
print(stu1.course)         # ['语文']
print(stu2.course)         # ['语文']
Student.course.append('英语')
print(Student.course)      # ['语文', '英语']
print(stu1.course)         # ['语文', '英语']
print(stu2.course)         # ['语文', '英语']

3.2:属性查找顺序与绑定方法

对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找。

1、类中定义的变量是类的数据属性,是共享给所有对象用的,指向相同的内存地址。

print(id(Student.school))
# 4376459376
print(id(stu1.school))
# 4376459376
print(id(stu2.school))
# 4376459376

2、类中定义的函数是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数。

Student.choose(stu1)
# json is choosing a course
Student.choose(stu2)
# lili is choosing a course

但其实类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同。

print(id(Student.choose))
# 4368304448
print(id(stu1.choose))
# 4368328576
print(id(stu2.choose))
# 4368328576

绑定到对象的方法特殊之处在于,绑定给谁就应该由谁来调用,谁来调用,就会将’谁’本身当做第一个参数自动传入(方法__init__也是一样的道理)

stu1.choose()     # 等同于Student.choose(stu1)
# json is choosing a course
stu2.choose()     # 等同于Student.choose(stu2)
# lili is choosing a course

注意:绑定到对象方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但命名为self是约定俗成的。