2009-05-21 19 views
6

यहां एक समेकित उदाहरण है कि हमारे कितने वर्ग बाइनरी प्रस्तुतियों (सी ++ द्वारा पढ़ा जा सकता है) लौटते हैं।बाइनरी के लिए अधिक पायथनिक रूपांतरण?

def to_binary(self): 
    'Return the binary representation as a string.' 
    data = [] 

    # Binary version number. 
    data.append(struct.pack('<I', [2])) 

    # Image size. 
    data.append(struct.pack('<II', *self.image.size)) 

    # Attribute count. 
    data.append(struct.pack('<I', len(self.attributes))) 

    # Attributes. 
    for attribute in self.attributes: 

     # Id. 
     data.append(struct.pack('<I', attribute.id)) 

     # Type. 
     data.append(struct.pack('<H', attribute.type)) 

     # Extra Type.   
     if attribute.type == 0: 
      data.append(struct.pack('<I', attribute.typeEx)) 

    return ''.join(data) 

मैं क्या नापसंद:

  • हर लाइन, data.append(struct.pack( साथ शुरू होता है लाइन की अनूठी भाग से ध्यान भंग।
  • बाइट ऑर्डर ('<') बार-बार दोहराया जाता है।
  • आपको बॉयलरप्लेट ''.join(data) वापस करना याद रखना होगा।

मैं क्या पसंद:

  • प्रारूप विनिर्देशक विशेषता नाम के पास दिखाई देते हैं। उदाहरण के लिए, यह देखना आसान है कि self.image.size दो हस्ताक्षरित इनट्स के रूप में लिखा गया है।
  • रेखाएं (अधिकतर) स्वतंत्र हैं। उदाहरण के लिए, 'विशेषता' से आईडी फ़ील्ड को निकालने के लिए, आपको कोड की एक से अधिक पंक्तियों को स्पर्श करने की आवश्यकता नहीं है।

क्या ऐसा करने के लिए एक और अधिक पठनीय/पायथनिक तरीका है?

उत्तर

4
from StringIO import StringIO 
import struct 

class BinaryIO(StringIO): 
    def writepack(self, fmt, *values): 
     self.write(struct.pack('<' + fmt, *values)) 

def to_binary_example(): 
    data = BinaryIO() 
    data.writepack('I', 42) 
    data.writepack('II', 1, 2) 
    return data.getvalue() 
4

आप अपने डेटा के लिए declarative syntax किसी प्रकार को लागू करने का प्रयास कर सकते हैं।

कौन सा की तरह कुछ में हो सकता है:

class Image(SomeClassWithMetamagic): 
    type = PackedValue(2) 
    attribute = PackedValue('attributes') # accessed via self.__dict__ 

#or using decorators 
    @pack("<II") 
    def get_size(): 
     pass 

#and a generic function in the Superclass 
    def get_packed(): 
     stuff 

आदि ...

अन्य उदाहरण SQLAlchemy के declarative_base, ToscaWidgets हो सकता है और

+0

घोषणात्मक वाक्यविन्यास अच्छा है यदि आपको क्रमबद्धता बनाने के लिए जटिल प्रोग्रामेटिक तर्क की आवश्यकता नहीं है (यानी बहुत सारे ifs और fors)। मैंने एक बाइनरी फ़ाइलफॉर्मेट के लिए एक बार में serialization, deserialization और स्वचालित रूप से जेनरेट किए गए दस्तावेज़ निर्दिष्ट करने के लिए घोषणात्मक दृष्टिकोण का उपयोग किया है। –

0

sprox हैं आप अपने कोड refactor सकता है एक में बॉयलरप्लेट रैप करने के लिए कक्षा। की तरह कुछ:

def to_binary(self): 
    'Return the binary representation as a string.' 
    binary = BinaryWrapper() 

    # Binary version number. 
    binary.pack('<I', [2]) 

    # alternatively, you can pass an array 
    stuff = [ 
     ('<II', *self.image.size),   # Image size. 
     ('<I', len(self.attributes)),  # Attribute count 
    ] 
    binary.pack_all(stuff) 

    return binary.get_packed() 
1
def to_binary(self): 
    struct_i_pack = struct.Struct('<I').pack 
    struct_ii_pack = struct.Struct('<II').pack 
    struct_h_pack = struct.Struct('<H').pack 
    struct_ih_pack = struct.Struct('<IH').pack 
    struct_ihi_pack = struct.Struct('<IHI').pack 

    return ''.join([ 
     struct_i_pack(2), 
     struct_ii_pack(*self.image.size), 
     struct_i_pack(len(self.attributes)), 
     ''.join([ 
      struct_ih_pack(a.id, a.type) if a.type else struct_ihi_pack(a.id, a.type, a.typeEx) 
      for a in attributes 
     ]) 
    ]) 
0

सबसे खराब समस्या यह है कि आप उत्पादन को पढ़ने के लिए सी में कोड इसी की जरूरत ++ है। क्या आप उचित रूप से पढ़ने और लिखने के कोड दोनों को व्यवस्थित रूप से प्राप्त करने या सामान्य विनिर्देश का उपयोग करने की व्यवस्था कर सकते हैं? इसके बारे में कैसे जाना है आपके सी ++ पर जितना पाइथन की जरूरत है।

0

आप इस तरह आसानी से पुनरावृत्ति से छुटकारा पा सकते हैं, जबकि अभी भी पठनीय:

def to_binary(self):  
    output = struct.pack(
     '<IIII', 2, self.image.size[0], self.image.size[1], len(self.attributes) 
    ) 
    return output + ''.join(
     struct.pack('<IHI', attribute.id, attribute.type, attribute.typeEx) 
     for attribute in self.attributes 
    ) 
+0

मुझे लगता है कि आप चूक गए "अगर attribute.type == 0:" –

2

तुम सिर्फ अच्छे वाक्य रचना चाहते हैं, आप का दुरुपयोग कर सकते हैं जनरेटर/सज्जाकार:

from functools import wraps  

def packed(g): 
    '''a decorator that packs the list data items 
    that is generated by the decorated function 
    ''' 
    @wraps(g) 
    def wrapper(*p, **kw): 
    data = [] 
    for params in g(*p, **kw): 
     fmt = params[0] 
     fields = params[1:] 
     data.append(struct.pack('<'+fmt, *fields)) 
    return ''.join(data)  
    return wrapper 

@packed 
def as_binary(self): 
    '''just |yield|s the data items that should be packed 
    by the decorator 
    ''' 
    yield 'I', [2] 
    yield 'II', self.image.size[0], self.image.size[1] 
    yield 'I', len(self.attributes) 

    for attribute in self.attributes: 
    yield 'I', attribute.id 
    yield 'H', attribute.type 
    if attribute.type == 0: 
     yield 'I', attribute.typeEx 

मूल रूप से इस का उपयोग करता है जनरेटर "मोनैड" को लागू करने के लिए, एक अमूर्त आमतौर पर हास्केल जैसे कार्यात्मक भाषाओं में पाया जाता है। यह कोड से कुछ मूल्यों की पीढ़ी को अलग करता है जो यह तय करता है कि इन मानों को एकसाथ कैसे जोड़ना है। यह तब एक कार्यात्मक प्रोग्रामिंग दृष्टिकोण है जो "पायथनिक" है, लेकिन मुझे लगता है कि यह पठनीयता में सुधार करता है।

+0

+1। मैं वास्तव में एक ही समाधान को पोस्ट करने के कुछ ही सेकंड दूर था। पठनीयता को बढ़ाने के लिए एक छोटा सुधार एक समारोह में डेटाटाइप स्ट्रिंग को समाहित करना होगा ताकि 'I' उत्पन्न हो, attribute.id उपज UIU (attribute.id) बन जाता है। –

2

कैसे protocol buffers Google के व्यापक क्रॉस भाषा प्रारूप और डेटा साझा करने का प्रोटोकॉल।

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