我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈
方法
方法的概念
- 描述一个目标的行为动作。比如:一个人怎样吃、怎样喝…
- 方法和函数非常相似
- 都封装了一系列行为动作,
- 都可以被调用之后,执行一系列行为动作
- 方法和函数最主要的区别就是:调用方式
- 示例1:函数定义和调用
# 定义一个函数 def eat(): print(1) print(2) print(3) # 函数调用 eat()
- 示例2:方法定义和调用
# 定义一个类 class Person: # 定义一个方法 def eat2(self): print(1) print(2) print(3) # 实例化对象 p = Person() # 方法调用 p.eat2()
方法的分类
- 实例方法
- 类方法
- 静态方法
叫法规范
- 在Python中,一切皆对象,那么类的本质也是对象。所以当说对象的时候,就有点分不清楚到底是类还是类创建的对象
- 为了方便区分,所以对叫法进行了规范
- 类,也叫类对象
- 通过类创建的对象,实际是类实例化的结果,所以叫 实例
- 其实也就是纠正了前面讲的:类属性和对象属性,实际应该是
类属性
和实例属性
分类依据
-
根据方法的第一个参数必须接受的数据类型来进行划分
- 实例方法:第一个参数需要接收到一个实例
- 类 方 法:第一个参数需要接收到一个类
- 静态方法:第一个参数不默认接收任何类型
-
示例代码
class ClassName: def instance_func(self): print('这是一个实例方法', self) @classmethod def class_func(cls): print('这是一个类方法', cls) @staticmethod def static_func(): print('这是一个静态方法') c = ClassName() print(c) # <__main__.ClassName object at 0x000001820A26CF10> c.instance_func() # 这是一个实例方法 <__main__.ClassName object at 0x000001820A26CF10> ClassName.class_func() # 这是一个类方法 <class '__main__.ClassName'> # 通过实例调用,会忽略实例,并自动将实例对应的类当做参数传递 c.class_func() # 这是一个类方法 <class '__main__.ClassName'> ClassName.static_func() # 这是一个静态方法 c.static_func() # 这是一个静态方法 # 通过类直接调用实例方法,会报错 # ClassName.instance_func() # TypeError: instance_func() missing 1 required positional argument: 'self' ClassName().instance_func() # 这是一个实例方法 <__main__.ClassName object at 0x0000015E5626CDC0>
方法的内存存储
- 不管是哪一种类型的方法,都是存储在类当中(存储在类的
__dict__
属性字典中)
方法的调用
- 不同类型的方法调用方式不同,但是,不管怎么调用,把握一个原则:
- 不管是自己传递,还是解释器帮我们处理,最终要保证不同类型的方法第一个参数接收到的数据是它们想要的类型
实例方法
- 第一个参数需要接收到一个实例
- 定义
- 语法
class ClassName: def instance_func(self, arg1, ...): print('这是一个实例方法', self) # 这里的self参数是一个形参,只是默认用self,其实可以修改为任何变量,与*args, **kwargs一样
- 语法
- 调用
-
标准调用(通过实例调用
实例.实例方法(实参1, ...) # 使用实例调用方法,解释器会自动把调用对象本身传递过去 # 如果实例方法没有接收任何参数,则会报错(一个自动传,一个不接收)
-
通过类调用(基本不用)
类名.实例方法(实例, 实参1, ...) # 通过类调用实例方法,需要手动传入第一参数,传入一个实例对象
-
间接调用
变量 = 类名.实例方法 变量(实例, 实参1, ...) # 本质就是直接找到函数本身来调用
-
类方法
- 第一个参数需要接收到一个类
- 定义
- 语法
class ClassName: @classmethod def class_func(cls, arg1, ...): print('这是一个类方法', cls)
- 语法
- 调用
- 通过类进行调用
类.类方法(实参1, ...)
- 通过实例进行调用
实例.类方法(实参1, ...) # 通过实例调用,会忽略实例对象,并自动将实例对应的类对象当做参数传递
- 间接调用
变量 = 实例.类方法 变量(实参1, ...)
- 通过类进行调用
- 补充
- 如果为派生类调用类方法,则派生类对象作为隐含的第一个参数传递
- 如果子类调用这个类方法,那么子类对象将作为第一个参数进行传递
- 示例
class ClassName: @classmethod def class_func(cls): print('这是一个类方法', cls) class ClassSub(ClassName): pass ClassSub.class_func() # 这是一个类方法 <class '__main__.ClassSub'>
静态方法
- 第一个参数不默认接收任何类型
- 定义
- 语法
class ClassName: @staticmethod def static_func(arg1, ...): print('这是一个静态方法')
- 语法
- 调用
- 通过类进行调用
类.静态方法(实参1, ...) # 通过实例调用,会忽略类对象,不会将类对象当做参数传递
- 通过实例进行调用
实例.静态方法(实参1, ...) # 通过实例调用,会忽略实例对象,不会将实例对象当做参数传递
- 间接调用
变量 = 实例.静态方法 变量(实参1, ...)
- 通过类进行调用
方法定义原则
- 根据方法内部使用对象来确定
- 如果在方法内部需要使用到实例对象本身的,则定义实例方法
- 如果在方法内部需要使用到类对象本身的,则定义类方法
- 如果在方法内部既不需要使用实例对象,也不需要使用类对象的,则定义静态方法
不同方法访问不同属性规律
- 不同类型的方法中访问不同类型属性的权限
- 实例方法:既可以访问实例属性,也可以访问类属性
- 类方法:只可以访问类属性,不能访问实例属性
- 静态方法:不能访问实例属性,也不能直接访问类属性,但可以通过
- 示例代码
class ClassName: b = '类属性' def instance_func(self): print(self) # <__main__.ClassName object at 0x0000029090ECCF10> print(self.a) # 实例属性 print(self.b) # 类属性 @classmethod def class_func(cls): print(cls) # <class '__main__.ClassName'> print(cls.b) # 类属性 # 类方法不能访问实例属性,会报错 # print(cls.a) # AttributeError: type object 'ClassName' has no attribute 'a' @staticmethod def static_func(): # print(a) # 静态方法无法访问实例属性 # print(b) # 静态方法无法直接访问类属性 print(ClassName.b) # 类属性 c = ClassName() c.a = '实例属性' # # 通过实例调用实例方法 # c.instance_func() # # 通过类调用类方法 # ClassName.class_func() # # 通过实例调用类方法 # c.class_func() # # 通过类调用静态方法 # ClassName.static_func() # # 通过实例调用静态方法 # c.static_func()
- 理解
# 定义一个类 class Person: # 定义一个类属性并赋值 age = 36 # 实例化一个对象,并赋值给p p = Person() # 给实例对象增加属性 p.name = '张三' print(p.name) # 张三 print(p.age) # 36 # 可以难过类对象直接访问类属性 print(Person.age) # 36 # 不能通过类对象直接访问实例属性,会报错 # print(Person.name) # AttributeError: type object 'Person' has no attribute 'name'
- 前面我们学习属性的时候讲到,通过实例对象可以访问类属性,是因为访问机制(先从自身找,找不到再到类里面找)
- 个人理解:这个访问机制,其实就是Python中作用域的LEGB规则(递归函数)
- 当通过实例对象访问类属性时,先在自身找这个属性,找不到时,通过
__class__
查找到对应的类对象,再到类对象中查找这个属性- 通过实例对象可以访问实例属性,也可以访问类属性
- 通过类对象只能访问类属性,不能访问到实例属性
- 所以
- 在调用实例方法时,会自动将示例对象传递给实例方法中的
self
参数,此时self
就是实例对象本身,所以可以通过self.实例属性
访问实例属性,也可以通过self.类属性
访问类属性 - 在调用类方法时,会自动将类对象传递给类方法中的
cls
参数,此时cls
就是类对象本身,所以可以通过cls.类属性
访问类属性,但不能通过cls.实例属性
访问实例属性 - 静态方法既不传实例对象也不传类对象,所以在静态方法中无法获取到实例对象和类对象,所以无法访问到实例属性和类属性,只能通过
类对象.类属性
访问类属性,但是基本不会用到这种(因为在方法中需要操作类对象相关,那就可以直接定义类方法了)
- 在调用实例方法时,会自动将示例对象传递给实例方法中的