2010-02-21 6 views
8

से structs की सरणी पास करें [अद्यतन: समस्या हल हो गई! पोस्ट के निचले]पाइथन से सी

मैं अजगर डेवलपर्स मेरी एपीआई, जो सी ++ पायथन सी एपीआई के माध्यम से मैन्युअल रूप से अवगत कराया इंटरफेस की एक श्रृंखला है में पैक डेटा की एक सरणी (इस मामले कोने में) पारित करने के लिए अनुमति देने के लिए की आवश्यकता है।

class Vertex(Structure): 
_fields_ = [ 
    ('x', c_float), 
    ('y', c_float), 
    ('z', c_float), 
    ('u', c_float), 
    ('v', c_float), 
    ('color', c_int) 
] 

verts = (Vertex * 3)() 
verts[0] = Vertex(0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF) 
verts[1] = Vertex(0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF) 
verts[2] = Vertex(-0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF) 

device.ReadVertices(verts, 3) # This is the interfaces to the C++ object 

कहाँ समारोह मैं करने के लिए पारित करने के लिए कोशिश कर रहा हूँ निम्नलिखित हस्ताक्षर हैं:

void Device::ReadVertices(Vertex* verts, int count); 

और इस के साथ मेरी प्रारंभिक छाप इस तरह एक अंतरफलक के लिए अनुमति देने के लिए ctypes संरचना वर्ग का उपयोग करने के लिए है अजगर आवरण इस तरह दिखता है:

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args) 
{ 
    PyObject* py_verts; 
    int count; 

    if(!PyArg_ParseTuple(args, "Oi", &py_verts, &count)) 
     return NULL; 

    // This Doesn't Work! 
    Vertex* verts = static_cast<Vertex*>(PyCObject_AsVoidPtr(py_verts)); 

    self->device->ReadVertices(verts, count); 

    Py_RETURN_NONE; 
} 
बेशक

, सबसे बड़ी समस्या मैं यह है: मैं struct के लिए PyObject प्राप्त कर सकते हैं, लेकिन मैं पता नहीं कैसे मैं यह करने के लिए डाली होता है सही प्रकार उपरोक्त कोड बुरी तरह विफल रहता है। तो मैं उपयोगकर्ता को इस तरह के डेटा को पायथन से पास करने की इजाजत देने के बारे में कैसे कहूंगा?

अब, कुछ चीजों पर विचार करने के लिए: सबसे पहले यह है कि मेरे पास पहले से ही मेरी पाइथन/सी ++ परत लिखी गई है, और मैं इसके साथ पूरी तरह से खुश हूं (मैं एसडब्ल्यूआईजी से दूर चले गए ताकि मुझे और अधिक लचीलापन मिल सके)। मैं इसे फिर से कोड नहीं करना चाहता, इसलिए मैं एक समाधान पसंद करूंगा जो सी एपीआई के साथ काम करता है। दूसरा, मेरा इरादा है कि वेरटेक्स संरचना को मेरे सी ++ कोड में पूर्व-परिभाषित किया जाए, इसलिए मैं उपयोगकर्ता को पायथन में इसे फिर से परिभाषित करने की आवश्यकता नहीं रखूंगा (इस तरह त्रुटियों पर कटौती), लेकिन मैं हूं सुनिश्चित नहीं है कि इस तरह एक संगत संरचना का पर्दाफाश कैसे करें। तीसरा, मेरे पास ऐसा करने का एक और तरीका नहीं जानने से सीटीपीएस संरचना को अलग करने का कोई कारण नहीं है। किसी भी सुझाव का स्वागत है। आखिरकार, चूंकि यह एक ग्राफिक्स ऐप के लिए है (जैसा कि आपने अनुमान लगाया होगा), मैं एक सुविधाजनक विधि पर एक तेज विधि पसंद करूंगा, भले ही तेज विधि थोड़ा और काम करे।

किसी भी मदद के लिए धन्यवाद! मैं अभी भी पाइथन एक्सटेंशन के आसपास अपना रास्ता महसूस कर रहा हूं, इसलिए कुछ स्टिकियर भागों पर सामुदायिक इनपुट प्राप्त करने में यह बहुत मददगार है।

[समाधान]

तो सबसे पहले बंद, हर किसी के लिए धन्यवाद, जो अपने विचारों में खड़ा किया। यह बहुत कम tidbits था जो अंतिम जवाब में जोड़ा गया। अंत में मुझे जो मिला वह है: सैम का स्ट्रक्चर.pack का उपयोग करने का सुझाव पैसे पर सही रहा। यह देखते हुए कि मैं अजगर 3 उपयोग कर रहा हूँ, मैं इतना थोड़ा कभी यह बदलाव करने के लिए किया था, लेकिन जब सभी ने कहा था और किया यह वास्तव में अपनी स्क्रीन पर दिखाया जा रहा एक त्रिकोण है:

verts = bytes() 
verts += struct.pack("fffffI", 0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF) 
verts += struct.pack("fffffI", 0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF) 
verts += struct.pack("fffffI", -0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF) 

device.ReadVertices(verts, 3) 
मेरी टपल पार्स अब की तरह लग रही के साथ

इस:

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args) 
{ 
    void* py_verts; 
    int len, count; 

    if(!PyArg_ParseTuple(args, "y#i", &py_verts, &len, &count)) 
     return NULL; 

    // Works now! 
    Vertex* verts = static_cast<Vertex*>(py_verts); 

    self->device->ReadVertices(verts, count); 

    Py_RETURN_NONE; 
} 

नोट है कि भले ही मैं इस उदाहरण में len चर का उपयोग नहीं करते हैं (हालांकि मैं होगा अंतिम उत्पाद में) मैं तो बस 'y' के बजाय 'वाई #' का उपयोग कर टपल पार्स करने के लिए की जरूरत है अन्यथा यह पहले न्यूल (दस्तावेज़ीकरण के अनुसार) पर रुक जाएगा। यह भी माना जा सकता है: शून्य * इस तरह कास्ट काफी खतरनाक है, इसलिए कृपया यहां दिखाए जाने से अधिक त्रुटि जांच लोड करें!

तो, अच्छी तरह से काम किया, खुश दिन, पैक और घर जाओ, हाँ?

रुको! इतना शीघ्र नही! अभी और है!

इस बारे में अच्छा लगा कि यह सब कैसे काम करता है, मैंने देखा कि मेरा पिछला प्रयास अभी भी मुझ पर उड़ा है और इस पोस्ट में पाइथन के पहले स्निपेट पर वापस लौटा है। (बिल्कुल नए सी कोड का उपयोग कर) और ... यह काम किया! परिणाम struct.pack संस्करण के समान थे! वाह!

तो इसका मतलब है कि आपके उपयोगकर्ताओं के पास इस तरह का डेटा प्रदान करने के तरीके में कोई विकल्प है, और आपका कोड या तो कोई बदलाव नहीं कर सकता है। व्यक्तिगत रूप से मैं ctype को प्रोत्साहित करने जा रहा हूं। संरचना विधि, क्योंकि मुझे लगता है कि यह आसान पठनीयता के लिए बनाता है, लेकिन वास्तव में यह भी है कि उपयोगकर्ता जो भी आरामदायक है। (हेक, वे मैन्युअल रूप से हेक्स में बाइट्स की एक स्ट्रिंग टाइप कर सकते हैं। यह काम करता है। मैंने कोशिश की।)

ईमानदारी से मुझे लगता है कि यह सबसे अच्छा संभव परिणाम है, इसलिए मैं उत्साहित हूं। आप सभी को धन्यवाद, और इस समस्या में चलने वाले किसी और को शुभकामनाएँ!

+0

क्या आपने boost :: python का उपयोग करने पर विचार किया है? – Anycorn

+0

हां, मैंने SWIG की कोशिश करने से पहले इसे आजमाया। मुझे एसडब्ल्यूआईजी का उपयोग करना आसान हो गया (बहुत कम अतिरिक्त कोड और आपको समान प्रदर्शन के साथ चलने वाले राक्षसों को संकलित करने की आवश्यकता नहीं है)। अंत में, हालांकि, मैं SWIG की तुलना में अधिक नियंत्रण चाहता था (उदाहरण के लिए, एसडब्ल्यूआईजी आपको पाइथन गुणों का पर्दाफाश करने का कोई रास्ता नहीं देता है) और इसलिए रैपर करने के लिए चुना गया था, जो वास्तव में आपको एक बार दर्द रहित होने के बाद बाहर निकला मूल बातें नीचे, मेरे कोड का उल्लेख नहीं करना अब बहुत तेज है। :) – Toji

+0

अनुमोदित, वे उन दोनों के लिए अच्छी पुस्तकालय हैं जो सी-एपीआई को दुबला नहीं करना चाहते हैं। वे सिर्फ मेरी जरूरतों के अनुरूप नहीं थे। – Toji

उत्तर

2

परीक्षण नहीं किया गया है लेकिन आपको इसे आज़माएं और हमें बताएं कि क्या यह आपकी आवश्यकताओं के लिए पर्याप्त तेज़ है।

पायथन पक्ष पर, किसी ऑब्जेक्ट की बजाय स्ट्रिंग में चरम को पैक करें।

str = "" # byte stream for encoding data 
str += struct.pack("5f i", vert1.x, vert1.y, vert1.z, vert1.u, vert1.v, vert1.color) # 5 floats and an int 
# same for other vertices 

device. ReadVertices(verts, 3) # send vertices to C library

सी पुस्तकालय/अजगर आवरण पर, प्रारूप स्ट्रिंग "si" उपयोग करने के लिए अपने PyArgs_ParseTuple संशोधित करते हैं। यह आपकी पायथन स्ट्रिंग को एक सी स्ट्रिंग (char *) में परिवर्तित करेगा जिसे आप अपने वेक्टर स्ट्रक्चर में पॉइंटर के रूप में टाइपकास्ट कर सकते हैं। इस बिंदु पर सी स्ट्रिंग बाइट्स/शब्दों/फ्लोट्स की एक धारा है और जो आप खोज रहे हैं वह होना चाहिए।

शुभकामनाएं!

+0

धन्यवाद। मैं उम्मीद कर रहा था की तुलना में थोड़ा सा clunkier, लेकिन मैं इसे आज़माउंगा! – Toji

+0

हाँ, यह सबसे तेज़ समाधान नहीं है ... लेकिन इसकी सुंदर भाषा अज्ञेयवादी है, और सी वास्तव में काम करने के लिए वास्तव में कम स्तर है। उम्मीद है की यह मदद करेगा! –

+0

अच्छी तरह से आंकड़े जाओ, न केवल यह काम किया बल्कि यह भी मुझे दिखाया कि मेरा पहला दृष्टिकोण कैसे काम करना है! वाह! बहुत बहुत धन्यवाद, और विवरण के लिए ऊपर मेरे अपडेट देखें। – Toji

1

सबसे आसान चीज जो मैं कर सकता हूं, वह पूरी तरह से इस मुद्दे से बचने और एक डिवाइस_ReadVertex का पर्दाफाश करना होगा जो एक्स, वाई, जेड, यू, वी और रंग को तर्क के रूप में लेता है। इसमें स्पष्ट कमी है, जैसे कि पाइथन प्रोग्रामर इसे एक-एक करके चिपकते हैं।

यदि यह पर्याप्त नहीं है (ऐसा लगता है कि यह नहीं है), तो आप here वर्णित एक नए पायथन प्रकार को परिभाषित करने का प्रयास कर सकते हैं। यह थोड़ा और कोड है लेकिन मुझे लगता है कि यह "अधिक वास्तुकलात्मक ध्वनि" विधि है, क्योंकि आप सुनिश्चित करते हैं कि आपके पायथन डेवलपर्स एक ही प्रकार की परिभाषा का उपयोग कर रहे हैं जैसे आप सी कोड में हैं। यह एक साधारण संरचना की तुलना में थोड़ी अधिक लचीलापन की अनुमति देता है (यह वास्तव में एक वर्ग है, जिसमें विधियों को जोड़ने की क्षमता आदि शामिल है), जो मुझे यकीन नहीं है कि आपको वास्तव में आवश्यकता है लेकिन यह बाद में काम में आ सकता है।

+0

मैं वर्तमान में अपने एपीआई के हिस्से के रूप में लगभग 10 या नए प्रकार को परिभाषित कर रहा हूं, इसलिए यह मेरे लिए कोई समस्या नहीं है। प्रश्न वास्तव में यह है कि उपयोगकर्ता मुझे उस जानकारी को एक संगत सरणी के रूप में कैसे खिला सकता है (विशेष रूप से पाइथन प्रकारों के साथ, जिसमें प्रत्येक उदाहरण के लिए टाइप हेडर ओवरहेड होना चाहिए।) – Toji

+0

आह, मैं देखता हूं। आप स्पेस उपयोग के साथ-साथ सीपीयू उपयोग के बारे में बहुत कुछ परवाह करते हैं, है ना? मुझे लगता है कि संरचना उत्तर सैम पोस्ट नीचे दिया गया है जैसा कि आप प्राप्त करेंगे, लेकिन मेरे अनुभव से संरचना मॉड्यूल पैक करने और अनपॅक करने के लिए बहुत सारे CPU का उपयोग करता है। ऐसा लगता है कि आप प्रकार के ढांचे के साथ सबसे अच्छे ट्रैक पर हो सकते हैं। मैं यह देखने के लिए चारों ओर देखूंगा कि क्या मैं यह नहीं समझ सकता कि आपकी संरचना ठीक से क्यों नहीं आ रही है। – xitrium

+0

मुझे अंतरिक्ष की परवाह करने की ज़रूरत है, क्योंकि यह डेटा डायरेक्टएक्स या ओपनजीएल को पारित करने का इरादा है। जबकि आप वहां नॉन-कसकर पैक किए गए डेटा से दूर हो सकते हैं, तो अगर आप ऐसा नहीं करते हैं तो यह सबसे अच्छा है क्योंकि अन्यथा आप जंक डेटा के साथ अपनी वीडियो मेमोरी भरेंगे। क्यों संरचना के माध्यम से नहीं आ रहा है, मुझे यह हल हो गया है। मैं एक पल में सवाल अपडेट करूंगा। – Toji

संबंधित मुद्दे