【python基础之面向对象的绑定方法与非绑定方法】--面向对象的绑定方法与非绑定方法

发布时间 2024-01-04 15:41:58作者: Unfool
title:  【python基础之面向对象的绑定方法与非绑定方法】--面向对象的绑定方法与非绑定方法
date:  2024-01-04  15:00:06 
updated: 2024-01-04 15:30:00
description:  相关类和对象属性的介绍以及绑定方法与非绑定方法
cover: 
       https://home.cnblogs.com/u/dream-ze/
	   https://www.cnblogs.com/songshutai/p/16858107.html

【一】类属性和对象属性

1、定义

类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享。

实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self是谁调用,它的值就属于该对象。

2、总结

访问类属性和对象属性总结:

类的属性可以使用类名访问(推荐) 类的属性也可以通过对象访问(不推荐)
对象的属性可以使用对象访问(推荐) 对象的属性不可以通过类名访问(报错)
在项目中 类的属性一般通过类名访问 对象的属性一般通过对象访问

修改类的属性和对象的属性的总结:

类可以修改类的属性 对象在修改类的属性的时候,其实是动态的给当前对象添加了一个属性.其他的对象不能访问修改后的值.
对象可以修改对象的属性 类也可以修改对象的属性.
在项目中 一般情况下,通过类名去修改类的属性 通过对象名去修改对象的属性.

3、示例

# 【一】类属性 : 分为两种 一种是数据属性 一种是函数属性
class Student:
    # 这个 school 其实就是数据属性,对象可以任意调用
    school = '清华大学'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    # 函数属性
    def read(self):
        print(f'正在读书')


# 实例化类得到类对象
stu = Student(name='dream', age=18, gender='male')

# 【一】访问数据属性的两种方法
# print(Student.__dict__)  # {'__module__': '__main__', 'school': '清华大学', '__init__': <function Student.__init__ at 0x0000029FF85A4400>, 'read': <function Student.read at 0x0000029FF860F920>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
# 一种是 通过 __dict__ 的字典取键
# print(Student.__dict__['school'])  # 清华大学
# 另一种直接通过 类名.属性 获取到属性的值
# print(Student.school)  # 清华大学

# 对象可以通过 __dict__ 获取到类属性码?
# print(stu.__dict__)  # {'name': 'dream', 'age': 18, 'gender': 'male'}
# print(stu.__dict__['school'])  # {'name': 'dream', 'age': 18, 'gender': 'male'}
# print(stu.school)  # 清华大学

# 【二】访问函数属性的两种方法
# print(Student.__dict__)
# 类调用对象函数属性 因为有一个位置参数叫 self ,类调用需要传入 self 实例化出来的对象
Student.__dict__['read'](stu)
# 对象调用函数属性,这里的位置参数会自动将调用该方法的对象传入,所以不用传self参数
# print(stu.__dict__) # 这里是没有的
stu.read()

【二】对象属性的查找顺序

# 对象的属性查找顺序
# 【1】首先从自己本身开始找 从 stu.__dict__ 开始找
# 【2】找不到再去实例化他的类中找 从 Student.__dict__ 开始找
# 【3】别的方法没有初始化过这个属性,并且这个类没有继承其他的类
# 【4】找不到就报错了

# 总结 : obj(对象) ---> class(类) ---> gender_class(父类) ---> 找不到直接报错

【三】类的特殊方法

class Cat():
    ...
from new_class import Cat
# 【一】定义一个类
class Animal():
    ...

class BlackCat(Cat):
    ...
class People:
    '''这是一个人类的注释'''

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        '''
        这是一个注释
        :return:
        '''
        print(f"{self.name} can run!")


# def login_auth(func):
#     def inner():
#         # 查看函数的名字
#         print(func.__name__) # index
#         return func()
#     return inner

# @login_auth
# def index():
#     ...
# index()

# 【1】实例化类得到对象
person = People(name='dream', age=18)
# 【二】类的名字
# def check_class_name(class_name):
#     print(class_name.__name__)
# check_class_name(class_name=People)
# check_class_name(class_name=Animal)
# 【三】查看类的文档字符串,查看类中的多行注释内容 ('''''' / """""")
# def check_class_name(class_name):
#     print(class_name.__doc__)
# check_class_name(class_name=People) # 这是一个人类的注释
# check_class_name(class_name=Animal) # None
# 【四】类的字典属性
# def check_class_name(class_name):
#     print(class_name.__dict__)
# check_class_name(class_name=People) # 这是一个人类的注释
# check_class_name(class_name=Animal) # None
# 【五】查看类定义所在的模块
# def check_class_name(class_name):
#     print(class_name.__module__)
# check_class_name(class_name=People) # __main__
# check_class_name(class_name=Animal) # __main__
# check_class_name(class_name=Cat) # new_class
# 【六】查看当前实例所对应的类
def check_class_name(obj_name):
    print(obj_name.__class__)
check_class_name(obj_name=People(name='dream',age=18)) # __main__
check_class_name(obj_name=Animal()) # __main__
check_class_name(obj_name=Cat()) # new_class

【四】绑定方法与非绑定方法

1、绑定方法

1.1、定义

凡是类中的方法或函数,默认情况下都是绑定给对象使用的。

类中不被任何装饰器装 装饰的方法或函数,默认情况下都是绑定给对象使用的,例如 def fun()  或 def fun(self)

用@classmethod装饰的方法是绑定到类上的

用@staticmethod修饰的方法,是解除所有绑定关系作为普通函数存在,为非绑定方法

1.2、特点

其特点是「调用方」本身自动作为第一个参数传入。

一个方法绑定到谁身上,谁来调用,该调用者当作第一个参数会自动传参。

绑定给对象:调用方是一个「对象」,该对象自动传入(调用方是『类』,需要手动传入第一个参数)

绑定给类:调用方是「类|对象」,该类自动传入

1.3、分类

绑定到类的方法:

用classmethod装饰器装饰的方法就是类绑定方法(「对象」也可调用「类绑定方法」,但仍将类当作第一个参数传入)。

类.boud_method(),自动将「类」当作第一个参数传入

对象.boud_method(),自动将「类」当作第一个参数传入

绑定到对象的方法:

没有被任何装饰器装饰的方法,默认是绑定给对象使用的方法。

对象.boud_method(args2,args3),自动将“对象”当作第一个参数传入。

类.boud_method(args1,args2,args3),需按照参数规则一一传递所有参数

    -- “类”可以调用“对象的绑定方法”,但不会自动传值,需按照参数规则一一传递所有参数

2、非绑定方法

2.1、定义

在类内部用@staticmethod装饰的函数即「非绑定方法」,就是普通函数。

2.2、特点

不与类或对象绑定

没有自动传参的效果

『类和对象』都可以调用

不管谁来调用,都不会自动传值

2.3、疑问点

自由方法应该也算非绑定方法?
		-- 自由方法是对象的绑定方法,绑定给对象。

如果定义staticmethod时传self或cls,还算是非绑定方法吗?

  -- 在静态方法里面 访问不了  类或者实例 的任何属性。 一般不需要传参数self

【注意】在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,不是普通函数,对象调用该方法会自动传值

3、总结

当「对象」调用「对象的绑定方法」时,默认把对象自己当做第一个参数传递到函数中

当 「类」 调用「对象的绑定方法」时,不会进行自动传值的;也就是说,函数有几个参数,我们就得传递进去几个参数。

当「类|对象」在调用「类的绑定方法」时,会默认把 类 当作参数传递进去。

当「类|对象」在调用「非绑定方法」时,不会自动传值

4、代码及部分文字描述

# 【一】绑定方法:绑定给某个目标(类或对象)的方法 --- 动态方法
# 【1】绑定给对象的方法
# class Student:  # 类的属性有两种:一种是数据属性 一种是函数属性
#     # 【1】数据属性
#     school = '清华大学'
#
#     # 【2】函数属性
#     def read(self, name):
#         print(f' {name} 正在读书')
# (1)实例化得到对象,对象调用对象的绑定方法
# stu = Student()
# 在这里对象调用绑定给对象的绑定方法时,会自动将当前对象作为第一个参数传入
# stu.read('dream') #  dream 正在读书
# (2)类调用对象的绑定方法
# Student.read('dream') # Student.read() missing 1 required positional argument: 'name'
# Student.read(name='dream') # TypeError: Student.read() missing 1 required positional argument: 'self'
# 如果是类调用对象的绑定方法,那么就需要将对象作为参数传进去
# stu = Student()
# Student.read(stu,'dream') #  dream 正在读书
# 在Python里面一切皆对象,八大基本数据类型全是对象,包括 None
# Student.read('521','dream')
# Student.read(None,'dream')
# (3)总结:
# 对象调用绑定给对象的方法,不需要传额外的参数,直接能调用执行
# 类调用绑定给对象的方法,第一个位置参数必须是实例化得到的对象,加其他可能传入的额外的参数

# 【2】绑定给类的方法
# class Student:  # 类的属性有两种:一种是数据属性 一种是函数属性
#     # 【1】数据属性
#     school = '清华大学'
#
#     # 【2】函数属性 -- 绑定给对象的方法
#     def read(self, name):
#         print(f' {name} 正在读书')
#     # 【3】函数属性 --- 绑定给类的方法
#     @classmethod # 装饰器的语法糖
#     def write(cls,name):
#         print(cls) # <class '__main__.Student'>
#         print(f' {name} 正在写作业')
# (1)对象调用绑定给类的方法,这里会自动检索到当前实例化得到当前对象的类,然后将类作为cls的参数传入
# stu = Student()
# stu.write(name='dream')
# (2)类调用绑定给类的方法,将调用此方法的类,作为cls的参数自动传入
# Student.write(name='hope')
# (3)总结
# 对象调用绑定给类的方法,不需要传入额外的参数,会自动将当前实例化此对象的类作为参数传入
# 类调用绑定给类的方法,不需要额外的传入参数,会自动将调用次方法的类作为参数传进去

# 【二】非绑定方法:不绑定给某个目标(类或对象)的方法 -- 静态方法
class Student:  # 类的属性有两种:一种是数据属性 一种是函数属性
    # 【1】数据属性
    school = '清华大学'

    # 【2】函数属性 -- 绑定给对象的方法
    def read(self,name):
        print(name)
        print(f' {name} 正在读书')

    # 【3】函数属性 --- 绑定给类的方法
    @classmethod  # 装饰器的语法糖
    def write(cls, name):
        print(cls)  # <class '__main__.Student'>
        print(f' {name} 正在写作业')

    # 【3】函数属性 --- 非绑定方法,本质上其实就是一个普普通通的函数
    @staticmethod
    def run(name):
        print(f' {name} 正在跑步')


# (1)对象调用非绑定方法.不需要传额外的参数
# stu = Student()
# stu.run(name='dream')
# stu.read(name='dream')
# (2)类调用绑定方法.不需要传额外的参数
# Student.run(name='hope')
# Student.read(name='hope')
# (3)总结:
# 对象调用非绑定方法,不需要传额外的参数
# 类调用非绑定方法,不需要传额外的参数

【五】绑定方法与非绑定方法总结

# 总结 : 绑定方法 与 非绑定方法

# 【一】概念上来说
# 绑定方法 : 就是绑定给某个目标(类或对象)的方法才叫绑定方法
# 非绑定方法:不绑定给某个目标(类或对象)的方法叫非绑定方法

# 【二】调用方式上来看
# 绑定给对象的方法:对象可以任意调用,类可能会受到某些限制
# 绑定给类的方法:类可以任意调用,对象可能会受到某些影响
# 非绑定方法:不受类和对象的限制,可以任意调用

# 【三】定义方式上来看
class Person():
    # 【1】绑定给对象的方法:正常我们定义的所有方法都是绑定给对象的方法
    # 在定义方法的时候,会自动补全 self
    def read(self):
        print(self)

    # 【2】绑定给类的方法:用装饰器装饰我们想要绑定给类的方法
    # 在定义方法的时候,会自动补全 cls
    @classmethod
    def write(cls):
        print(cls)

    # 【3】非绑定方法:既不绑定给对象也不绑定给类
    # 在定义方法的时候,不会自动补全参数
    @staticmethod
    def run():
        ...


# 【四】三种函数的调用
# 【1】绑定给对象的方法
# (1)对象调用
p = Person()
p.read()
# (2)类调用,self的值就是实例化得到的对象
Person.read(Person())
# 【2】绑定给类的方法
# (1)类调用
Person.write()
# (2)对象调用
p = Person()
p.write()
# 【3】静态方法(非绑定方法)
# (1)对象调用
p = Person()
p.run()
# (2)类调用
Person.run()