Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Monkey补丁类派生自ctypes.Union不';行不通_Python_Ctypes_Monkeypatching - Fatal编程技术网

Python Monkey补丁类派生自ctypes.Union不';行不通

Python Monkey补丁类派生自ctypes.Union不';行不通,python,ctypes,monkeypatching,Python,Ctypes,Monkeypatching,我试图“猴子补丁”一个从PythonCtypes“Union”派生的类,但我无法做到这一点——出现奇怪的错误,有时还出现seg错误。当从ctypes“Structure”派生时,同样的事情也非常有效 我已经把范围缩小到最简单的测试用例,我在下面发布。我正在使用Python 3.6.4。我想知道我是否做错了什么(或者ctypes“Union”实现是否有问题?)。请参阅下面的代码和相应的输出 import ctypes def display(self): """ A new kind of

我试图“猴子补丁”一个从PythonCtypes“Union”派生的类,但我无法做到这一点——出现奇怪的错误,有时还出现seg错误。当从ctypes“Structure”派生时,同样的事情也非常有效

我已经把范围缩小到最简单的测试用例,我在下面发布。我正在使用Python 3.6.4。我想知道我是否做错了什么(或者ctypes“Union”实现是否有问题?)。请参阅下面的代码和相应的输出

import ctypes

def display(self):
  """ A new kind of display """
  return f'Print Type #2: ( {self.y1}, {self.y2} )'

class MyStruct(ctypes.Structure):
  _fields_ = [ 
      ('y1', ctypes.c_uint32),
      ('y2', ctypes.c_uint32)
      ] 

  def __str__(self):
    return f'Print Type #1: [ {self.y1}, {self.y2} ]'

class MyUnion(ctypes.Union):
  _fields_ = [ 
      ('y1', ctypes.c_uint32),
      ('y2', ctypes.c_uint32)
      ] 

  def __str__(self):
    return f'Print Type #1: [ {self.y1}, {self.y2} ]'

if __name__ == '__main__':

  a = MyStruct()
  a.y1 = 10
  a.y2 = 20

  print('Using Structure:')
  print('----------------')
  print(a)
  print('Original :', MyStruct.__str__)
  # monkey patch  __str__ with a different function.
  MyStruct.__str__ = display
  print('Patched :', MyStruct.__str__)
  print('Patched (dict) :', MyStruct.__dict__['__str__'])
  print(a)

  a = MyUnion()
  a.y1 = 10
  a.y2 = 20

  print('Using Union:')
  print('------------')
  print(a)
  print('Original :', MyUnion.__str__)
  # monkey patch  __str__ with a different function.
  MyUnion.__str__ = display
  print('Patched :', MyUnion.__str__)
  print('Patched (dict) :', MyUnion.__dict__['__str__'])
  print(a)
这是我运行程序时的输出

Using Structure:
----------------
Print Type #1: [ 10, 20 ]
Original : <function MyStruct.__str__ at 0x7fdf89d02e18>
Patched : <function display at 0x7fdf8b0ebe18>
Patched (dict) : <function display at 0x7fdf8b0ebe18>
Print Type #2: ( 10, 20 )
Using Union:
------------
Print Type #1: [ 20, 20 ]
Original : <function MyUnion.__str__ at 0x7fdf89d02f28>
Patched : <function MyUnion.__str__ at 0x7fdf89d02f28>
Patched (dict) : <function display at 0x7fdf8b0ebe18>
Traceback (most recent call last):
  File "ctypes_bug.py", line 54, in <module>
    print(a)
TypeError: 'managedbuffer' object is not callable
使用结构:
----------------
打印类型#1:[10,20]
原件:
修补:
修补(dict):
打印类型#2:(10,20)
使用Union:
------------
打印类型#1:[20,20]
原件:
修补:
修补(dict):
回溯(最近一次呼叫最后一次):
文件“ctypes_bug.py”,第54行,在
印刷品(a)
TypeError:“managedbuffer”对象不可调用
显然,当相应的Python对象从“Structure”派生时,我能够“patch”
\uuuu str\uuu
,但当相应的Python对象从“Union”派生时,我无法“patch”
\uuu str\uuu

有趣的是,
MyUnion.\uuuuuu dict\uuuu[\ uuuu str\uuuu]
MyUnion.\uuuuuuu str\uuuuu
显示了不同的结果,这也很奇怪


我有什么地方做错了吗?我非常感谢任何帮助或见解

我想这里有一个真正的CPython bug。结构类型的for type对象使用
PyType\u type.tp\u setattro

static int
PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
    /* XXX Should we disallow deleting _fields_? */
    if (-1 == PyType_Type.tp_setattro(self, key, value))
        return -1;

    if (value && PyUnicode_Check(key) &&
        _PyUnicode_EqualToASCIIString(key, "_fields_"))
        return PyCStructUnionType_update_stgdict(self, value, 1);
    return 0;
}
但是使用
PyObject\u GenericSetAttr

static int
UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
    /* XXX Should we disallow deleting _fields_? */
    if (-1 == PyObject_GenericSetAttr(self, key, value))
        return -1;

    if (PyUnicode_Check(key) &&
        _PyUnicode_EqualToASCIIString(key, "_fields_"))
        return PyCStructUnionType_update_stgdict(self, value, 0);
    return 0;
}

必须使用
PyType\u Type.tp\u setattro
来更新类型插槽并使类型无效
PyObject\u GenericSetAttr
不知道它应该做这两件事中的任何一件,这会由于“僵尸”缓存属性而导致潜在的内存损坏。看起来structs的bug与2008年初的一样,但它们忘记了处理联合。

我刚刚打开“答案编辑器”来说明同样的问题。UnionType是一个元类,因此它应该使用
PyType\u Type.tp\u setattro
。此外,更改集的链接更好:@MartijnPieters:Ah,这更好。我没有找到那个,因为git的指责。谢谢你解开了这个谜。我想知道是否有一个简单的方法来解决这个问题?我使用的是组织范围的Python安装,无法使用本地编译的CPython进行安装。我正在使用的ctypes是使用types.new_class自动生成的。@user2357112:合并告诉我它现在可能在一个发布分支上,因为2.6是trunk,当时我确实在那里找到了它。祝贺你成为少数第一次发布ctypes的人之一!