DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • python面向过程

  • python面向对象

    • OOP基本
    • 继承和组合
    • 多态与多态性
    • 封装与接口
    • 绑定与非绑定方法
    • 简单总结
    • 反射、内置方法
    • 元类
    • 异常处理
    • 小项目之course_select
    • 复习
  • 网络并发编程

  • 不基础的py基础

  • 设计模式

  • python_Need
  • python面向对象
DC
2022-10-05

简单总结

python3统一了类与类型的概念. 类即类型.

obj.属性 -- 即属性引用
★ 类的两大操作
  1. "属性引用"
     类的定义里的属性 = 数据属性 + 函数属性
        1> 在类的定义阶段("注意!不是类实例化的时候哦")就会执行类里面的代码,开辟一个namescope
        2> namescope(类)中的属性是共享给所有的类实例化对象的 【共有属性】
  2. "类实例化"
        调用类对象/类的实例化 会开辟一个个空的namescope.
        类实例化对象开辟一个空的scope后,紧接着就会触发绑定方法__init__的执行,初始化实例化对象
        会将类的实例化obj作为绑定方法的第一个形参(约定俗称是self)的值传入
        注意: __init__里面不可有return
★ 类的实例化对象可进行"属性引用"!!
    1. 引用数据属性
        1> 类中的数据属性
        2> 独有的(优先级最高) namescope(类实例化)里面存放的就是实例化对象的【独有属性】
    2. 引用方法属性
        即类中的函数属性 "方法是‘从属于’对象的函数"
        Ps:方法不是类实例所特有的,比如列表对象也具有append、insert等方法 【类就是类型】
           d = {'x': 1} 本质上是 d = dict({'x':1})

namescope(类)、namescope(实例化对象)都可通过 "obj.__dict__"查看namescope里面的属性

代码块(模块、函数、类)执行代码时,以及类的实例化的时候,会开辟namespace.
特别注意的是,函数里函数体的代码在调用时执行!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from types import MethodType, FunctionType


a = 5
def f():
    pass

# -- 注意哈!!有个空字典的结果返回,并不意味着开辟了一个空的命名空间,函数在调用的时候才会开辟命名空间
print(f.__dict__)  # {}

# -- 类A在定义阶段就会执行里面的代码,开辟命名空间.(不是在实例化的时候开辟哦!!)
class A:
    a = 3

    # -- 此处namespace(类A)里已经对a名称进行了绑定 {a:3}
    print(a)  # 3

    # -- 类A还在定义的过程中,全局命名空间里还没有A
    # -- 准确点说,这里涉及到【类中变量引用的规则】,官方解释:
    #    1> 未绑定的局部变量将在全局命名空间中查找
    #    2> 在类代码块中定义的名称的作用域/namespace作用范围,不会扩展到方法的代码块中
    #       包括列表推导式和生成器表达式 Ps:可以通过 obj.属性 -- 即属性引用的方式来进行访问
    # print(A.a)  # NameError:name 'A' is not defined

    def __init__(self, name):
        self.name = 'dc'

    def fun1(self):
        pass

    @classmethod
    def fun2(self):
        pass

    @staticmethod
    def foo():
        # -- 这里涉及到类中变量引用的规则
        print(a)  # 5


# -- 类的实例化会先开辟一个命名空间,然后通过__init__进行初始化存放该实例化对象独有的数据属性
x = A('dc')
print(x)  # <__main__.A object at 0x7fbcebe8dca0>
print(A)  # <class '__main__.A'>
"""
一般单独def的变量是函数对象.
被@classmethod装饰的函数属性,不管是类还是实例化对象进行属性引用,引用的都是PyMethodObject方法对象.
第一个参数是self的函数属性,被实例化对象进行属性引用,引用的是PyMethodObject方法对象.
除此之外,进行的属性引用(eg:@staticmethod),引用的都是PyFunctionObject函数对象.

函数定义: PyCodeObject + def == PyFunctionObject"函数对象"
类定义:
     有"self"特征的PyFunctionObject 将与类实例化对象进行绑定 进化为 PyMethodObject"方法对象"
     有"@classmethod"特征的PyFunctionObject 将与类对象进行绑定 进化为 PyMethodObject"方法对象"
PyMethodObject和PyFunctionObject在调用时进化成PyFrameObject,开辟一块命名空间,执行函数体代码.
"""
# -- 通过`from types import MethodType, FunctionType`来判断
#    类实例化对象引用的方法属性是函数对象还是方法对象 前者是<function ...> 后者是<bound method ...> 
train_list = [
    f,       # <function f at 0x7fbcebe8a9d0>是函数对象!
    A.fun1,  # <function A.fun1 at 0x7fbcebe8aa60>是函数对象!
    x.fun1,  # <bound method A.fun1 of <__main__.A object at 0x7fbcebe8dca0>>是方法对象!
    A.fun2,  # <bound method A.fun2 of <class '__main__.A'>>是方法对象!
    x.fun2,  # <bound method A.fun2 of <class '__main__.A'>>是方法对象!
    A.foo,   # <function A.foo at 0x7fbcebe8aaf0>是函数对象!
    x.foo,   # <function A.foo at 0x7fbcebe8aaf0>是函数对象!
]
for item in train_list:
    if isinstance(item, FunctionType):
        print(f"{item}是函数对象!")
    else:
        print(f"{item}是方法对象!")
A.foo()
print(x.fun1.__dict__)  # {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class A:
    def f1(self):
        pass

    def f2(self):
        # 不加self报错!
        # 也许你会想,执行`m()` namescope(f2)里面没有的话,就去namescope(A)里面找???
        # 注意哦,【类中变量引用的规则】
        # m()  # NameError:name 'm' is not defined
        self.m()

    @staticmethod  # -- 静态方法,意味着不会自动绑定类实例化对象
    def m():
        pass

a = A()
b = A()
a.f1()
b.f1()
a.f2()

"""
分析如下:
"""
1> a.f1()的本质是 A.f1(a) 
   a.f1()、b.f1()进行方法的绑定,相当于A进行了两次函数调用,函数调用会开辟新的命名空间
   所以这里a.f1()、b.f1()开辟的命名空间是不一样的.
2> a.f1 is b.f1 的结果为False 
   虽然a.f1和b.f1在这个过程中引用的都是namescope(类A)中同一个PyFunctionObject f1
   但f1分别与a和b进行绑定后,进化出来的PyMethodObject是不同的
   换个说法:
       Pyhon是动态语言.对象和类的成员并不一定会一致
       通过a.f1这样获得的对象,并不是真正的A.f1,对与不同的类实例来说也不是同一个对象.
       这是因为a.f1返回的是一个将实例a绑定到了self上的新创建的一个临时的bound method.
       (a.f1是生成了一个捆绑A.f1和a的临时对象)
       当调用a.f1(*args)的时候其实是调用了A.f1(a, *args),
       是一个把实例本身当作第一个参数也就是self传进去的封装了一层的函数.
3> a.m is b.m 的结果为True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
绑定与非绑定方法
反射、内置方法

← 绑定与非绑定方法 反射、内置方法→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式