Path: csiph.com!usenet.pasdenom.info!news.redatomik.org!newsfeed.xs4all.nl!newsfeed3a.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'languages.': 0.04; 'importing': 0.05; 'output': 0.05; 'sys': 0.07; '(instead': 0.09; '__name__': 0.09; 'caller': 0.09; 'etc).': 0.09; 'image,': 0.09; 'pil': 0.09; 'pixels': 0.09; 'trailing': 0.09; 'python': 0.11; 'wrote': 0.14; 'anyway': 0.14; 'creates': 0.14; '"&"': 0.16; '%r"': 0.16; "'__main__':": 0.16; '(0,': 0.16; '(1,': 0.16; '(without': 0.16; '.py': 0.16; 'accident.': 0.16; 'bitwise': 0.16; 'bryan': 0.16; 'byte,': 0.16; 'coord': 0.16; 'elements,': 0.16; 'emit': 0.16; 'from:addr:cs': 0.16; 'from:addr:zip.com.au': 0.16; 'from:name:cameron simpson': 0.16; 'message-id:@cskk.homeip.net': 0.16; 'png': 0.16; 'popping': 0.16; 'pythonic': 0.16; 'said.': 0.16; 'sees': 0.16; 'simpson': 0.16; 'skip:> 20': 0.16; 'sys.stderr': 0.16; 'terribly': 0.16; 'think.': 0.16; 'value;': 0.16; 'weekend.': 0.16; 'y):': 0.16; 'exception': 0.16; 'wrote:': 0.18; 'bit': 0.19; 'module': 0.19; '(where': 0.19; 'file,': 0.19; 'normally': 0.19; 'later': 0.20; 'not,': 0.20; 'example': 0.22; 'import': 0.22; 'issue.': 0.22; 'otherwise,': 0.22; 'print': 0.22; 'header:User-Agent:1': 0.23; 'error': 0.23; '"you': 0.24; 'byte': 0.24; 'flows': 0.24; 'laws': 0.24; 'script.': 0.24; 'skip': 0.24; 'subject:Code': 0.24; 'tend': 0.24; 'cheers,': 0.24; 'script': 0.25; 'extension': 0.26; 'this:': 0.26; 'least': 0.26; 'values': 0.27; 'gets': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'wondering': 0.29; '(this': 0.29; 'array': 0.29; 'generally': 0.29; 'raise': 0.29; 'statement': 0.30; 'subject:please': 0.30; 'program,': 0.31; 'code': 0.31; "skip:' 10": 0.31; 'end,': 0.31; 'file:': 0.31; 'img': 0.31; 'invoke': 0.31; 'origin': 0.31; 'os,': 0.31; 'pos': 0.31; 'allows': 0.31; 'file': 0.32; 'probably': 0.32; 'becomes': 0.33; 'programmers': 0.33; 'actual': 0.34; "i'd": 0.34; 'could': 0.34; 'problem': 0.35; 'something': 0.35; 'etc': 0.35; 'objects': 0.35; 'operations': 0.35; 'but': 0.35; 'representing': 0.36; 'skip:> 10': 0.36; 'done': 0.36; 'charset:us-ascii': 0.36; 'thanks': 0.36; 'should': 0.36; 'changing': 0.37; 'turn': 0.37; 'list': 0.37; 'skip:o 20': 0.38; 'handle': 0.38; 'to:addr:python-list': 0.38; 'list,': 0.38; 'short': 0.38; 'anything': 0.39; 'does': 0.39; 'entire': 0.61; 'content-disposition:inline': 0.62; 'email addr:gmail.com': 0.63; 'happen': 0.63; 'myself': 0.63; 'become': 0.64; 'more': 0.64; 'here': 0.66; '>from': 0.68; 'below.': 0.71; 'funny': 0.74; 'friend': 0.79; 'forth': 0.81; 'directed': 0.83; 'low': 0.83; 'avoids': 0.84; 'bare': 0.84; 'blow': 0.84; 'received:192.168.15': 0.84; 'standing': 0.84; 'want:': 0.84; 'destination': 0.91; 'write:': 0.91 Date: Wed, 8 Apr 2015 09:49:18 +1000 From: Cameron Simpson To: python-list@python.org Subject: Re: Code critique please MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline In-Reply-To: <53f4c2fd-a20c-4d09-8719-8f3f9b80670b@googlegroups.com> User-Agent: Mutt/1.5.23 (2014-03-12) References: <53f4c2fd-a20c-4d09-8719-8f3f9b80670b@googlegroups.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 167 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1428450564 news.xs4all.nl 2926 [2001:888:2000:d::a6]:59226 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:88631 On 07Apr2015 15:43, kai.peters@gmail.com wrote: >I just wrote this bit (coming from Pascal) and am wondering how seasoned Python programmers would have done the same? Anything terribly non-python? > >As always, thanks for all input. >K > >""" > Creates a PNG image from EPD file >""" > >import os, sys >from PIL import Image, ImageFont, ImageDraw > ># ----------------------------------------------------------------------------- >def RenderByte(draw, byte, x, y): > blist = list(bin(byte).lstrip('0b')) # turn byte into list with 8 elements, Remark: .lstrip does not do what you think. You want: blist = list(bin(byte)[2:]) # turn byte into list with 8 elements, to skip over the leading "0b". Otherwise, with lstrip, consider what would happen with a low value byte, with multiple leading zeroes. (Actually, on reflection, you might get away with it - but probably not, and anyway would be fragile against changing the ordering of the bits.) I'd be popping off the least or most siginificant bit myself with "&" and "<<" or ">>". It might be wordier, bit it would be more in keeping with the actual bitwise operations going on. > c = 0 # each representing one bit > for bit in blist: > if bit: > draw.point((x + c, y), fcolor) > c += 1 This might be more Pythonic written: for c, bit in enumerate(blist): which will emit (0, b0), (1, b1) and so forth for bit 0, bit 1 etc (where bit 0 is the leftmost from your list, etc). Avoids the "c = 0" and the "c += 1" and also makes your loop robust against adding control flows later which might skip the final "c += 1" at the end, even by accident. > return You generally do not need a trailing return with no value; it is implicit. >def EPD_2_Image(edpfilename, imagefilename): > # get out of here if EPD file not present > if not os.path.isfile(epdfilename): > print 'file not found: ' + edpfilename > return Traditionally one would raise an exception instead of returning. Eg: if not os.path.isfile(epdfilename): raise ValueError("missing file: %r" % (epdfilename,)) and have the caller handle the issue. Similarly for all the other pre-checks below. Also, it is normal for error messages to be directed to sys.stderr (this allows them to be logged independently of the program's normal output; for example the normal output might be sent to a file, but the error messages would continue to be displayed on screen). So were you to iussue a print statement (instead of an exception) you would write: print >>sys.stderr, .... or in Python 3: print(...., file=sys.stderr) > # is this a valid EPD file? > filesize = os.path.getsize(epdfilename) > if (((xdim / 8) * ydim) + header) <> filesize: > print 'incorrect file size: ' + edpfilename > return > > # blow old destination file away > if os.path.isfile(imagefilename): > print 'deleting old dest. file: ' + imagefilename > os.remove(imagefilename) > > print 'processing...' > > # set up PIL objects > img = Image.new('1', (xdim, ydim), bcolor) # '1' = Bi-tonal image > draw = ImageDraw.Draw(img) > > # read entire EPD file into byte array (without the header) > content = bytearray(open(epdfilename, 'rb').read())[16:] > > # image coord origin at top/left according to PIL documentation > pos = 0 > for y in range(ydim): > x = 0 > for byte in range(xdim / 8): # 8 pixels 'stuffed' into one byte > RenderByte(draw, content[pos], x, y) > pos += 1 > x += 8 > > img.save(imagefilename) # format is inferred from given extension > print 'done.' > > return Again, this "return" can be implicit. ># ----------------------------------------------------------------------------- > >xdim = 1024 >ydim = 1280 >header = 16 >black = 0 >white = 1 >bcolor = black >fcolor = white > >epdfilename = 'c:\\temp\\drawtest2.epd' >imagefilename = 'c:\\temp\\drawtest2.png' Normally these values would be at the top of your program, and named in UPPER_CASE to indicate that they are like "constants" in other languages. So you might put this: XDIM = 1024 YDIM = 1280 HEADER_SIZE = 16 BLACK = 0 WHITE = 1 BCOLOR = BLACK FCOLOR = WHITE EPD_FILENAME = 'c:\\temp\\drawtest2.epd' IMAGE_FILENAME = 'c:\\temp\\drawtest2.png' at the top of the script. I notice you have a bare [16:] in your "content =" line. Should that not say "[HEADER_SIZE:]" ? >EPD_2_Image(epdfilename, imagefilename) I tend to write things like this as thought they could become python modules for reuse. (Often they do; why write something twice?) So the base of the script becomes like this: if __name__ == '__main__': EPD_2_Image(EPD_FILENAME, IMAGE_FILENAME) In this way, when you invoke the .py file directly __name__ is "__main__" and your function gets run. But it you move this all into a module which may be imported, __name__ will be the module name, an so not invoke the main function. The importing code can then do so as it sees fit. Cheers, Cameron Simpson I heard a funny one this weekend. I was belaying a friend on a very short problem and when she was pumped out she told me to "Let me down" and my other friend that was standing nearby said. "You were never UP!". - Bryan Laws