Today, I went for a stroll through the streets of Kitano and Kitakarasuyama.
大きな地図で見る
Meeting lots of cats and having happy moments with them.
Hide and seek? :-)
trial and errors
Today, I went for a stroll through the streets of Kitano and Kitakarasuyama.
Meeting lots of cats and having happy moments with them.
Hide and seek? :-)
Just use sys.hexversion instead of the string equivalent (sys.version, sys.version_info, ...). It's flexible and fast.
>>> import sys
>>> sys.hexversion
33882608
>>> hex(sys.hexversion)
'0x20501f0'
>>> if sys.hexversion >= 0x2050100:
... print "Python 2.5.1 or higher"
...
Python 2.5.1 or higher
For example, the explicit relative imports is introduced in Python 2.5, you can check this function as:
HAS_RELATIVE_IMPORTS = (sys.hexversion >= 0x2050000)
NOTE: sys.hexversion is available since 1.5.2. It's not worth to support older versions.
One of my favorite things about pylint is a feature that allows to disable/enable message for a block or statement.
For instance, consider the function below:
def scan_code(co, module):
assert co and module
if DEBUG: print co.co_filename
...
The function scan_code has so many debug prints. For performance reason, however, they are if DEBUG: print statements. Now pylint would report so many messages (C: means convention, for programming standard violation).
% pylint scan_code
...
C:107:scan_code: More than one statement on a single line
C:110:scan_code: More than one statement on a single line
C:114:scan_code: More than one statement on a single line
C:117:scan_code: More than one statement on a single line
C:123:scan_code: More than one statement on a single line
You can disable these messages for scan_code function. # pylint: disable-msg=... style comment can be used everywhere in the source code and affects a block or statement.
# pylint: disable-msg=C0321
def scan_code(co, module):
assert co and module
if DEBUG: print co.co_filename
...
Python's Generator expressions and Tuple pack/unpack is more powerful than I thought.
for k, v in d.iteritems():
if v > 123:
yield k, v
is equivalent to:
return (item for item in d.iteritems() if item[1] > 123)
Some simple generators can be coded using Generator expressions, and Tuple pack/unpack is an easy way to return multiple values.
% python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'apple': 256, 'hoge': 123, 'orange': 555}
>>>
>>> def fn_yield():
... for k, v in d.iteritems():
... if v > 123:
... yield k, v
...
>>> def fn_generator():
... return (item for item in d.iteritems() if item[1] > 123)
...
>>> for k, v in fn_yield():
... print k, v
...
orange 555
apple 256
>>> for k, v in fn_generator():
... print k, v
...
orange 555
apple 256
Do you know Universal Newline Support in Python? To be honest, I didn't know that. The PEP 278 describes in detail:
In a Python with universal newline support open() the mode parameter can also be "U", meaning "open for input as a text file with universal newline interpretation". Mode "rU" is also allowed, for symmetry with "rb". Mode "U" cannot be combined with other mode flags such as "+". Any line ending in the input file will be seen as a '\n' in Python, so little other code has to change to handle universal newlines.
Conversion of newlines happens in all calls that read data: read(), readline(), readlines(), etc.
Here is an example:
% printf 'Hello, World!\r\n' > /tmp/hello.txt
% cat /tmp/hello.txt
Hello, World!
% python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> open('/tmp/hello.txt').read()
'Hello, World!\r\n'
>>> open('/tmp/hello.txt', 'U').read()
'Hello, World!\n'
If Python was built with the --with-universal-newlines option to configure (the default), File objects have newlines attribute, so testing whether the current Python has universal newline support can be done with:
if hasattr(sys.__stdout__, "newlines"):
print "universal line endings"
py_compile and compileall module provides functions to generate a byte-code file from a source file. You can not, however, enable or disable byte code optimization at runtime.
The byte code optimization depends the built-in variable __debug__ in the current interpreter, and assignments to __debug__ are illegal. Python 2.2 (or later) is strict about that.
% python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> __debug__
True
>>> __debug__ = False
File "<stdin>", line 1
SyntaxError: can not assign to __debug__
So you can't enable/disable optimization flag without running another interpreter (using '-O' switch).
Why Python unittest module lacks assertNone/assertNotNone? I think this lack would cause problems as API misuse. For example:
obj = factory.make_object()
self.assert_(obj) # must not be None (?)
I intended to say "factory.make_object must not return None", but It can fail even False and such an empty object (0, "", [], ...).
I should have written like:
obj = factory.make_object()
self.assert_(obj is not None) # must not be None!
Repeating that code, however, is so boring, a lot of the visual noise, and error-prone. Writing assertNone/assertNotNone:
class TestCase(unittest.TestCase):
"""Custom TestCase class"""
def failUnlessNone(self, expr, msg=None):
"""Fail the test unless the expression is None."""
if expr is not None: raise self.failureException, msg
def failIfNone(self, expr, msg=None):
"""Fail the test if the expression is None."""
if expr is None: raise self.failureException, msg
# Synonyms for assertion methods
assertNone = failUnlessNone
assertNotNone = failIfNone
The following pylint command still outputs reports:
% pylint --reports=no module
versions and environment:
% uname -a
Darwin macbook3.local 9.4.0 Darwin Kernel Version 9.4.0: Mon Jun 9 19:30:53 PDT 2008; root:xnu-1228.5.20~1/RELEASE_I386 i386
% python --version
Python 2.5.1
% pylint --version
No config file found, using default configuration
pylint 0.15.0,
astng 0.17.3, common 0.35.0
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)]
on Mac OS X 10.5.4.
I gave a quick look at the pylint source code. Removing optparse's default option fixes this problem (see below), but I don't know why.
--- pylint_orig/lint.py 2008-09-14 18:49:35.000000000 +0900
+++ /Library/Python/2.5/site-packages/pylint-0.15.0-py2.5.egg/pylint/lint.py 2008-09-14 18:50:07.000000000 +0900
@@ -184,7 +184,7 @@
Reports (if any) will be written in a file name "pylint_global.[txt|html]".'}),
('reports',
- {'default': 1, 'type' : 'yn', 'metavar' : '',
+ {'type' : 'yn', 'metavar' : '',
'short': 'r',
'group': 'Reports',
'help' : 'Tells wether to display a full report or only the\