通过对象的地址获取对象

简介: 通过对象的地址获取对象

像 C, Go, Rust 这样的静态语言都有指针的概念,通过对指针解引用即可拿到指针指向的内存。而指针在 Cython 里面也是支持的,但前提指针指向的必须是 C 类型的变量。

cdef int n = 123
# 拿到 n 的地址
cdef int *p = &n
# Cython 里面不能使用 *p 来解引用
# 因为 * 有着其它的含义
# 我们需要使用 p[0] 来解引用
p[0] += 1
# 打印 n, 会发现被修改了
# 因为 p 指向的内存中保存的就是 n
print(n)  # 124

当对象是 C 类型的变量时,那么可以获取指针,因为对于 C 而言,变量就是内存的别名。但是 Python 不行,因为 Python 的变量存储就是对象的地址,我们可以通过 id 函数查看。

cdef list names = ["satori", "koishi", "marisa"]
# 我们不能使用 &names 获取列表对象的指针
# 因为 names 保存的本身就是列表对象的地址
print(id(names))  # 1918122496768
# 只不过 Python 在语言层面上摒弃了指针
# 所以我们叫它地址,但它不具备指针的含义
# 虽然以前一直说 Python 的变量本质上是 PyObject *
# 但那是站在 C 的角度上来说的,而 Python 没有指针
# 因此 id(names) 返回的就是一串数字
# 不过这里是 Cython,Cython 同时理解 C 和 Python
# 所以我们可以把 Python 的变量当成指针来用
print(
    <Py_ssize_t><void *>names
)  # 1918122496768
# 打印的结果仍然是一串数字

那么问题来了,我们能不能根据这一串数字,再反推出 Python 对象呢?

比如外界的 Python 代码将对象的地址传过来,我们根据地址来反推出这个对象是什么,你觉得可以办到吗?如果是纯 Python 的话,应该是办不到的,但有了 Cython 一切都有可能。

# 一个纯 Python 类型的变量,指向一个列表
names = ["satori", "koishi", "marisa"]
# 拿到它的地址
# 此时的 address 就是一串数字
address = id(names)
# 下面我们要进行反推了
print(
    <object><void *><Py_ssize_t>address
)  # ['satori', 'koishi', 'marisa']

怎么样,是不是很神奇呢?首先 void * 可以转成整数,那么整数也可以变成 void *,只不过这个整数需要是 C 的整数。转成 void * 之后,再转成 object 类型即可。

为了更直观地看到现象,我们封装一个函数:

def infer_object(Py_ssize_t address):
    return <object> <void *> address

文件名为 cython_test.pyx,我们测试一下:

import pyximport
pyximport.install(language_level=3)
from cython_test import infer_object
number = 666
print(
    infer_object(id(number))
)  # 666
name = "古明地觉"
print(
    infer_object(id(name))
)  # 古明地觉
class Girl:
    name = "古明地恋"
    age = 15
print(
    infer_object(id(Girl)).name,
    infer_object(id(Girl)).age
)  # 古明地恋 15

我们后续会介绍如何在 Cython 中引入 C,即便是 C 函数返回一个地址,我们也是可以拿到相应的值的。

E N D


相关文章
|
6月前
|
XML Java 数据格式
spring中怎么通过静态工厂和动态工厂获取对象以及怎么通过 FactoryBean 获取对象
spring中怎么通过静态工厂和动态工厂获取对象以及怎么通过 FactoryBean 获取对象
79 0
|
1月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
52 4
|
Java
使用反射获取对象属性的坑
使用反射获取对象属性的坑
42 0
|
Java
【JAVA】反射获取对象/LIST中对象属性
【JAVA】反射获取对象/LIST中对象属性
413 0
思考让人学有所得,学有所获
思考让人学有所得,学有所获
VB编程:获取对象私有域的地址-39
VB编程:获取对象私有域的地址-39
VB编程:获取对象私有域的地址
VB编程:获取对象私有域的地址
124 0
VB编程:获取对象私有域的地址
|
XML 前端开发 应用服务中间件
获取对象属性值改动的属性集合的正确姿势(拒绝大量If-else代码)
在业务场景中可能有这样的需求: 同一个类的两个对象(一个数数据库中获取的上一次的属性,一个是前端传来的修改过的属性),需要判断哪个属性被修改了。 那么有一些童鞋可能采用大量的if-else代码块对需要关注的属性进行判断。
143 0
Java反射获取对象中特定属性的值
Java反射获取对象中特定属性的值 问题一:如何找到某个对象中特定属性的值? public static Object getFieldValueByObject (Object object , String targetFieldName) throws Exception { ...
11041 0
|
JavaScript 数据格式 JSON
js获取对象长度和名称
1.对象的长度不能用.length获取,用js原生的Object.keys可以获取到 var obj = {'name' : 'Tom' , 'sex' : 'male' , 'age' : '14'};  var arr = Object.
1654 0