如何在Python中模拟指针?( 五 )

如何在Python中模拟指针?
文章插图
 
此代码定义了一个Metrics类 。该类仍然使用字典来保存实际数据,该数据位于_metrics成员变量中 。这将为您提供所需的可变性 。现在您只需要能够访问这些值 。一个很好的方法是使用属性:
这段代码利用了@property 。如果您不熟悉装饰器,可以查看Python装饰器入门 。@property装饰器允许您访问func_calls,cat_pictures_served,它们就像属性一样:

如何在Python中模拟指针?

文章插图
 
您可以把名称当作属性访问这一事实,意味着您已抽象了一个事实:这些值在字典中 。您还可以更明确地指出属性的名称是什么 。当然,您应该能够增加这些值:
如何在Python中模拟指针?

文章插图
 
您已了解了两种新方法:
1.inc_func_calls()
2.inc_cat_pics()
这些方法能够修改类中字典的值 。您现在有一个类可以修改,就像您正在修改指针一样:
如何在Python中模拟指针?

文章插图
 
这样,您就可以在应用程序中的各个位置访问func_calls和调用inc_func_calls(),并在Python中模拟指针 。当您需要在应用程序的各个部分中频繁使用和更新指针时,这非常有用 。
注意:特别是在这个类中,使用inc_func_calls()和inc_cat_pics()更为清楚明白,而不是使用@property.setter,这能阻止用户将这些值设置为任意的整型或无效的值,如字典 。
这是Metrics类的完整代码:
如何在Python中模拟指针?

文章插图
 
使用ctypes模块实现真实指针好吧,也许Python中有指针,特别是CPython 。使用内置ctypes模块,您可以在Python中创建真正的C风格指针 。如果您不熟悉ctypes,那么您可以查看使用C库扩展Python和“ctypes”模块 。
你要使用它的真正原因是你需要对C库创建一个需要指针的函数调用 。让我们回到之前的C函数add_one():
如何在Python中模拟指针?

文章插图
 
同样,这段代码将x的值增加1 。要使用它,首先将其编译为共享对象 。假设上述代码存储在add.c文件中,您可以通过gcc来完成以下操作:
如何在Python中模拟指针?

文章插图
 
第一个命令将C源文件编译为一个名为add.o的对象 。第二个命令获取该未链接的目标文件并生成一个名为libadd1.so的共享对象 。
libadd1.so应该在您当前的目录中 。您可以使用ctypes的命令将其加载到Python:
如何在Python中模拟指针?

文章插图
 
代码ctypes.CDLL返回一个代表libadd1的共享对象 。因为您add_one()在此共享对象中定义,所以您可以像访问其他任何Python对象一样访问它 。在调用该函数之前,您应该指定函数签名 。这有助于Python确保将正确的类型传递给函数 。
在这种情况下,函数签名是指向整数的指针 。ctypes允许您使用以下代码来指定:
如何在Python中模拟指针?

文章插图
 
在此代码中,您设置函数签名以匹配C所期望的内容 。现在,如果您尝试使用错误的类型调用此代码,那么您将得到一个很好的警告而不是未定义的行为:
如何在Python中模拟指针?

文章插图
 
Python抛出一个错误,解释说add_one()想要一个指针而不是一个整数 。幸运的是,ctypes有一种方法可以将指针传递给这些函数 。首先,声明一个C风格的整数:
如何在Python中模拟指针?

文章插图
 
上面的代码创建了一个C风格的整数x,其值为0 。ctypes提供方便的byref()方法,它允许通过引用来传递变量 。
注意:传递变量时,术语"通过引用"与"通过值"相反 。
通过引用传递时,您将引用传递给原始变量,因此修改将反映在原始变量中 。按值传递会生成原始变量的副本,并且修改不会反映在原始变量中 。
你可以用下面的代码来调用add_one():
如何在Python中模拟指针?

文章插图
 
太好了!你的整数加1 。恭喜,您已成功使用Python的真实指针 。
总结您现在对Python对象和指针之间的关系有了更好的理解 。尽管名称和变量之间的某些区别似乎很迂腐,但从根本上理解这些关键术语可以扩展您对Python如何处理变量的理解 。


推荐阅读