2017-09-25 108 views
0

我試圖將一些診斷添加到嵌套的ctypes結構,但未能如此,並想知道原因。什麼作品如預期的那樣裸機例如:無法將屬性添加到ctypes中的嵌套結構

import ctypes 

class FirstStruct(ctypes.Structure): 
    _fields_ = [('ch', ctypes.c_ubyte)] 

f = FirstStruct() 

print type(f) 
print hasattr(f, 'helper') 
f.helper = 'xyz' 
print hasattr(f, 'helper') 

這些行打印我的預期:

<class '__main__.FirstStruct'> 
False 
True 

但是,當我用這個作爲另一種結構失敗:

class SecondStruct(ctypes.Structure): 
    _fields_ = [('first', FirstStruct)] 

s = SecondStruct() 

print type(s.first) 
print hasattr(s.first, 'helper') 
s.first.helper = 'xyz' 
print hasattr(s.first, 'helper') 

以上結果爲

<class '__main__.FirstStruct'> 
False 
False 

有人可以解釋我的區別? (我跑它的Python 2.7.8你要知道,我不想改變結構本身,而是想添加ctypes的結構之外的額外的變量。)


編輯:

這裏有一個更直接的例子:

import ctypes 

class FirstStruct(ctypes.Structure): 
    _fields_ = [('ch', ctypes.c_ubyte)] 

class SecondStruct(ctypes.Structure): 
    _fields_ = [('first', FirstStruct)] 

f = FirstStruct() 
s = SecondStruct() 

f.helper = 'aaa' 
s.first.helper = 'bbb' 
s.first.ch = 0 
t = s.first 
t.helper = 'ccc' 
t.ch = 12 

print f.helper   # aaa 
print t.ch    # 12 
print s.first.ch  # 12 
print t.helper   # ccc 
print s.first.helper # AttributeError: 'FirstStruct' object has no attribute 'helper' 

的問題是:爲什麼不是s.firstt等價的,如果我CA,爲什麼不呢s.first.helper觸發警告畢竟沒有設置它?

+1

簡短的答案是ctype.Structures不可變。可變對象的賦值指向與源相同的內存位置。使用結構,即使保存類型(FirstStruct),也會創建一個新值。這意味着改變源,不會改變分配的變量。字典可能會爲你做詭計。你有沒有嘗試過使用字典作爲最高級別的容器? –

+0

@RonNorris對不起,我幾乎明白你寫了什麼......但還沒有。嘗試使用https://stackoverflow.com/a/4828831/501814回答一個不可變對象的概念,但是在嘗試分配一個新屬性時,這裏出現屬性錯誤(正如我期望從s.first中得到的那樣if它是真正不可變的。) 是不可變的s.first的ta可變版本,指向相同的ctypes內存位置,但來自具有'helper'屬性的不同位置,而s.first的更改版本會立即丟失,因爲s的不變性? – Andris

+1

非常。 's.helper ='sss''會像't.helper ='ccc'一樣工作,因爲你不會搞亂原始的FirstStruct對象 - 你實際上是在給's'添加一個屬性。 –

回答

0

在第二個示例中,s.first正在返回內部結構的副本。您可以通過查看其id()看到這一點:

>>> id(s.first) 
112955080L 
>>> id(s.first) # didn't change 
112955080L 
>>> f=s.first # capture a reference the object returned 
>>> id(f)  # still the same 
112955080L 
>>> id(s.first) # changed! 
113484232L 

發生了什麼事是返回保持被分配到同一地址的新副本,但立即釋放。參考後,副本在另一個地址。

所以你創建一個helper屬性,只是一個臨時對象。

在第一個示例中,f直接指向FirstStruct實例,因此您可以設置和讀取該屬性。

+0

謝謝。一個補充:底層的ctypes結構保持不變 - 所以ctypes.addressof(f)== ctypes.addressof(s.first),正如終於找到的[documentation line](https://docs.python.org/ 2/library/ctypes.html#surprises)_「請記住,從Structure,Unions和Arrays中檢索子對象不會複製子對象,而是檢索訪問根對象的底層緩衝區的包裝對象。 「_ – Andris

0

如果您使用複製模塊,則可以獲取您創建的ctype對象的當前快照。因此請嘗試:

import copy 
import ctypes 

class FirstStruct(ctypes.Structure): 
    _fields_ = [('ch', ctypes.c_ubyte)] 

f = FirstStruct() 

print type(f) 
print hasattr(f, 'helper') 
f.helper = 'xyz' 
print hasattr(f, 'helper') 

t = copy.copy(f) 
print hasattr(t, 'helper') 
>>> True 
+0

也許我的例子太抽象了。我有一個這樣的結構樹,它的一個分支中的一些值改變了另一部分必須被解碼的方式。因此,我想在SecondStruct中添加一個標誌給FirstStruct。 (不是它的副本。) – Andris