问:小编为什么突然开始发python?难道C语言你不行了?
废话少说,让我们进入python中的类的学习!!
(一)基本知识
(1)掌握类的概念
1、类的定义:
即用来描述具有 相同属性和方法 的对象的集合
2、示例:
就像int类,其中有100,20等不同的对象。(和C语言中的结构体类似)
(2)定义一个类
1、语法:
class Student:
pass #pass语句的作用就是占位,在还未确定好具体的内容的时候使用
2、 类 Student是对象吗?
在python中,只要是对象,那么就有地址,类型和值三个,
所以我们可以验证!!
代码如下:
class Student: pass print(id(Student)) print(type(Student)) print(Student)
由代码的结果我们可以知道,类也是对象!
(3)类的组成
1、示例
class Student:
my_home='甘肃' #类属性
def __init__(self,name,age):# __init__ 实例方法
self.name=name
self.age=age
def meat(self): #方法
print("喜欢吃肉")
@classmethod
def cm(cls):#类方法
print("类方法")
@staticmethod
def sm():#静态方法
print("静态方法")
由代码所示,类的组成一般就是这四个,不需要全部都存在(看具体情况,自行添加)
2、组成各部分的具体解释
(1)def __init__ (self,name,age):
self.name = name
self.age = age
在Python中,
def __init__(self):
是一个特殊的方法,被称为构造函数或初始化方法。它是在创建一个类的实例时自动调用的,用于初始化该实例的属性。
- 在
__init__(self)
方法的定义中,形参self必不可少
,而且必须位于其他形参的前面。Python调用这个方法来创建 Student 实例时,将自动传入实参self
。self
参数代表当前实例对象。通过self
,可以访问实例的属性和方法。- 在
__init__(self)
方法中,我们可以给实例对象设置初始值。可以通过self.属性名(注意,这个属性名可以是任何名称,并且与之后的调用是相对应的,但是(self,name,age)中的name和age尽量见名知意
)
来指定实例对象的属性,并为其赋予初始值。- 如何使用呢? 即在类之外使用 具体如下
person=Student('张三',20)#创建一个实例对象即就是给 name初始化为 ’张三‘ age初始化为20 。调用时,如果想打印 person中的值,可以写为如下代码print(person.name,person.name)
(2)def meat ( self ) :
print("喜欢吃肉")
在python中,def meat(self): 是 自定义的方法,参数为 self 。
在这个方法中,可以调用实例方法中的实例!!
- 在自定义方法中调用实例方法中的属性 如:person.meat() #注意这里一定是已经创建了一个person的实例对象,代码请看之前
(3) @classmethod
def cm(cls):#类方法
print("类方法")@staticmethod
def sm():#静态方法
print("静态方法")
- 这两种方法的调用类似,都是直接使用 类名.方法名 来调用,如下:
Student.cm() Student.sm()
(4)类属性
- 类中的方法外的变量,被所有的对象共享!
- 类属性的调用 上述的代码,即可调用写为 print (Student.my_home )
(二)动态绑定属性和方法
(1)动态绑定属性
在python中,类在定义好之后,可能有时候会涉及到某一个实例对象的属性不想再另外一个实例对象中使用,那么这个时候就需要动态绑定来解决
具体如下:还是上述建立的 Student类 首先创建两个实例对象 然后存储在 stu1 和stu2 中
代码如下
stu1 = Student('李四',20) stu2 = Student('王麻子',30)现在代码中是两个人的信息,现在已知的是 李四是个男的,需要打印出来,但是王麻子性别不知道,所以不打印,那么应该怎么做?
直接在 __init__(self) 方法中再加一个 性别属性?但是仔细想想,那样定义的属性是所有的实例对象共有的,所以是不行的,那就让我们使用动态绑定的方法来解决!
如下:
我们发现,第三行代码就是给stu1动态绑定一个属性,此时当stu2也试图使用的时候就会发生错误
(2)动态绑定方法
基本原理同上述动态绑定属性!
(1)和绑定属性一样,单独绑定一个方法需要在类之外
如下:
如图片所示,相当于定义了一个函数,然后单独绑定给了stu1,最后一行代码是调用。
(三)面向对象的三大特征
(1)封装
1、作用:提高程序的安全性
2、具体:就是将数据(类型)和行为(方法)包装到类对象中,并且隐藏对象的属性和实现的细节,只暴露调用方法
小技巧:可以在类中某个属性名称前面加上__(两个下划线),从而不希望在外部被访问;
我们发现这样对实例属性进行操作之后,就无法以正常的方式在类外调用
但是任然可以通过 dir()查出类中的所有属性,然后看具体应该如何使用,如下:
我们发现,stu1 所对应的 实例属性'_Student__brand' ,和其他如:name 不太相同,这说明是有着特定的语法能够调用的!
具体语法格式为 :stu1._Student__brand
(2)继承
1、语法格式:
class 子类名(父类1,父类2,...)
- 在python中,支持多继承
- 若没有填写父类,则默认继承 object类
- 定义子类的时候,必须在其构造函数中调用父类的构造函数
2、示例:
代码如下
class Person(object):#此处的子类为Person,父类为 object def __init__(self,name,age):#在Person类中有实例方法 self.name = name self.age = age def info(self): #在Person中定义一个方法 info,作用是打印实例属性 name和age print(self.name,self.age) class Student(Person):#此处的子类为Student ,父类为 Person def __init__(self,name,age,student_year):#此处为定义自己的实例方法,多了一个实例属性为 #student_year super().__init__(name,age)#继承其父类的实例方法,必须为super().父类方法名() self.student_year = student_year#属性重写 def info(self):#定义自己的方法 super().info()#继承父类的方法,必须为super().父类方法名() print(self.salary)#方法重写 class Teacher(Person):#原理同上 def __init__(self,name,age,teacher_year): super().__init__(name,age) self.teacher_year=teacher_year def info(self): super().info() print(self.teacher_year) stu=Student('zhangsan',20,5)#创建Student的类的实例对象,存放在stu中,其中包含在父类中继承的两个属性和自定义的一个属性 tea=Teacher('lisi',35,10)#同上 stu.info()#调用方法 tea.info()
在本代码中,有小编写的详细的注解,接下来图解上述代码,大家可以通过图片来理解!
(3)方法重写
1、即子类继承的父类中的属性和方法,对于子类来说是不足以支持子类的需求的,此时就需要对其进行重写
2、示例:
(1)属性重写;上述 继承 中的代码片段,有
对于这个父类,只有两个实例属性,最后创建好调用,可以打印姓名和年龄,但是很明显对于 Student 和Teacher两个子类是不足够的,那么就可以写为如下
我们不难发现,在两个子类中又加了属性分别为 student_year , teacher_year
方法重写:也在上述代码中有体现,你发现了吗?
(四)object类/多态
(1)object 类
1、定义
所有类的父类,所有类都有object类中的属性和方法
2、内置函数 dir
(1)作用,在之前我们已经提及,其作用就是可以查看所指定对象中的方法和属性
(2)用法:print(dir(某个对象名称))
(3)示例:查看object类
(4)重写 __str__ 方法
在python中,object类中的所有方法都是可以进行重写的,从而改变其原来的作用原理,来达到自己所需要的目的!
对于 str 方法,其默认是在使用print函数来打印类的对象的时候实现的,其作用是返回地址
1、未改写之前(代码还是上述 ‘继承’ 中的代码)
2、改写
def __str__(self): return '名字{0},今年{1}岁,当学生{2}年'.format(self.name,self.age,self.student_year)代码写在Student类中,
改写之后再次打印