pythonバージョンの確認方法あれこれ

pythonバージョンの確認方法あれこれ

気をつけないとミイラとりがミイラになたーり箱の鍵は箱の中になちゃうよー。

pure Python

pure python with standard bundled `platform’:

1 >>> import platform
2 >>> platform.python_version()
3 '2.7.9'
4 >>> platform.python_version_tuple()
5 ('2', '7', '9')


pure Python with standard bundled `sysconfig’ (2.7+):

1 >>> import sysconfig
2 >>> sysconfig.get_python_version()
3 '2.7'


pure python with standard bundled `distutils.sysconfig’ (2.6):

1 >>> import distutils.sysconfig
2 >>> distutils.sysconfig.get_python_version()
3 '2.6'


ほかにもあった気がするが忘れた。

2015/3/12追記:よりによって一番基礎的なの忘れてた

pure Python with standard bundled `sys’:

 1 Python 2.7.9 (default, Dec 10 2014, 12:28:03) [MSC v.1500 64 bit (AMD64)] on win32
 2 Type "help", "copyright", "credits" or "license" for more information.
 3 >>> import sys
 4 >>> sys.version
 5 '2.7.9 (default, Dec 10 2014, 12:28:03) [MSC v.1500 64 bit (AMD64)]'
 6 >>> sys.version < '3'
 7 True
 8 >>> sys.version >= '3'
 9 False
10 >>> 

このチェック方法、個人的には気持ち悪いんだけど、一番多い気がする。

sysconfigについて

sysconfig は色んな局面、特に setup.py で使うが、2.7 標準搭載のものにある「get_path」などが 2.6 の distutils.sysconfig には「まだない」かったりする。2.6、2.7 両方をサポートする必要がある場合困るので、2.7 の sysconfig.py、_sysconfigdata.py を抱え込んでしまうのも手。(まぁ setuptools とか他に頼るものがあればそれでも良い。)

python2.6だと、

 1 Python 2.6.9 (unknown, Mar  4 2015, 01:06:14) 
 2 [GCC 4.9.2 20141101 (Red Hat 4.9.2-1)] on linux3
 3 Type "help", "copyright", "credits" or "license" for more information.
 4 >>> import distutils.sysconfig
 5 >>> print("\n".join(dir(distutils.sysconfig)))
 6 DistutilsPlatformError
 7 EXEC_PREFIX
 8 PREFIX
 9 __builtins__
10 __doc__
11 __file__
12 __name__
13 __package__
14 __revision__
15 _config_vars
16 _findvar1_rx
17 _findvar2_rx
18 _init_mac
19 _init_nt
20 _init_os2
21 _init_posix
22 _python_build
23 _variable_rx
24 customize_compiler
25 expand_makefile_vars
26 get_config_h_filename
27 get_config_var
28 get_config_vars
29 get_makefile_filename
30 get_python_inc
31 get_python_lib
32 get_python_version
33 os
34 parse_config_h
35 parse_makefile
36 project_base
37 python_build
38 re
39 string
40 sys
41 >>>  

2.7で「格上げ」されてこうなった:

 1 Python 2.7.8 (default, Nov 10 2014, 08:19:18) 
 2 [GCC 4.9.2 20141101 (Red Hat 4.9.2-1)] on linux2
 3 Type "help", "copyright", "credits" or "license" for more information.
 4 >>> import sysconfig
 5 >>> print("\n".join(dir(sysconfig)))
 6 _CONFIG_VARS
 7 _EXEC_PREFIX
 8 _INSTALL_SCHEMES
 9 _PREFIX
10 _PROJECT_BASE
11 _PYTHON_BUILD
12 _PY_VERSION
13 _PY_VERSION_SHORT
14 _PY_VERSION_SHORT_NO_DOT
15 _SCHEME_KEYS
16 _USER_BASE
17 __builtins__
18 __doc__
19 __file__
20 __name__
21 __package__
22 _expand_vars
23 _extend_dict
24 _generate_posix_vars
25 _get_default_scheme
26 _get_makefile_filename
27 _getuserbase
28 _init_non_posix
29 _init_posix
30 _main
31 _parse_makefile
32 _print_dict
33 _safe_realpath
34 _subst_vars
35 get_config_h_filename
36 get_config_var
37 get_config_vars
38 get_path
39 get_path_names
40 get_paths
41 get_platform
42 get_python_version
43 get_scheme_names
44 is_python_build
45 os
46 pardir
47 parse_config_h
48 realpath
49 sys
50 >>> 

get_pathをどう使いたいかと言えば、

 1 #
 2 if sys.platform != 'win32':
 3     INCLUDES += ["-Iinclude", '-isystem"%s"' % (
 4         sysconfig.get_path('include'))]
 5     LIBS_BASE = ['rt']
 6     LIBPATHES = ['.'] + LIBPATH
 7 else:
 8     INCLUDES += ["-Iinclude", "-Imissing/include", '-I"%s"' % (
 9         sysconfig.get_path('include'))]
10     LIBS_BASE = []
11     LIBPATHES = ['.', sysconfig.get_path('data') + "/libs"] + LIBPATH

みたいに、C 拡張のビルドに必要なヘッダファイルの場所などなどを得たいわけだ。2.6 のものでもいいんだけど、2.7 のものの方がより柔軟だ、ってわけだ。

CPython C API

 1 #if PY_MAJOR_VERSION >= 3
 2   #undef PyIntObject
 3   #undef PyInt_Type
 4   #undef PyInt_Check
 5   #undef PyInt_CheckExact
 6   #undef PyInt_FromString
 7   #undef PyInt_FromUnicode
 8   #undef PyInt_FromLong
 9   #undef PyInt_FromSize_t
10   #undef PyInt_FromSsize_t
11   #undef PyInt_AsLong
12   #undef PyInt_AS_LONG
13   #undef PyInt_AsSsize_t
14   #undef PyInt_AsUnsignedLongMask
15   #undef PyInt_AsUnsignedLongLongMask
16 
17   #define PyIntObject                  PyLongObject
18   #define PyInt_Type                   PyLong_Type
19   #define PyInt_Check(op)              PyLong_Check(op)
20   #define PyInt_CheckExact(op)         PyLong_CheckExact(op)
21   #define PyInt_FromString             PyLong_FromString
22   #define PyInt_FromUnicode            PyLong_FromUnicode
23   #define PyInt_FromLong               PyLong_FromLong
24   #define PyInt_FromSize_t             PyLong_FromSize_t
25   #define PyInt_FromSsize_t            PyLong_FromSsize_t
26   #define PyInt_AsLong                 PyLong_AsLong
27   #define PyInt_AS_LONG                PyLong_AS_LONG
28   #define PyInt_AsSsize_t              PyLong_AsSsize_t
29   #define PyInt_AsUnsignedLongMask     PyLong_AsUnsignedLongMask
30   #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
31 #endif

PY_MINOR_VERSION もあるが、それよりは以下。

1 #if PY_VERSION_HEX >= 0x02070000
2     /* Python 2.7.0+ 用コード */
3 #else
4     /* 以外 */
5 #endif

なお、「全部」は patchlevel.h にあって、CPython 2.6.9 の場合以下の通り(patchlevel.h):

 1 /* Newfangled version identification scheme.
 2                                                               
 3    This scheme was added in Python 1.5.2b2; before that time, only PATCHLEVEL
 4    was available.  To test for presence of the scheme, test for
 5    defined(PY_MAJOR_VERSION).
 6 
 7    When the major or minor version changes, the VERSION variable in
 8    configure.in must also be changed.
 9 
10    There is also (independent) API version information in modsupport.h.
11 */
12 
13 /* Values for PY_RELEASE_LEVEL */
14 #define PY_RELEASE_LEVEL_ALPHA  0xA
15 #define PY_RELEASE_LEVEL_BETA   0xB
16 #define PY_RELEASE_LEVEL_GAMMA  0xC     /* For release candidates */
17 #define PY_RELEASE_LEVEL_FINAL  0xF     /* Serial should be 0 here */
18                                         /* Higher for patch releases */
19 
20 /* Version parsed out into numeric values */
21 /*--start constants--*/
22 #define PY_MAJOR_VERSION        2
23 #define PY_MINOR_VERSION        6
24 #define PY_MICRO_VERSION        9
25 #define PY_RELEASE_LEVEL        PY_RELEASE_LEVEL_FINAL
26 #define PY_RELEASE_SERIAL       0
27 
28 /* Version as a string */
29 #define PY_VERSION              "2.6.9"
30 /*--end constants--*/
31 
32 /* Subversion Revision number of this file (not of the repository) */
33 #define PY_PATCHLEVEL_REVISION  "$Revision$"
34 
35 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
36 
37    Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */
38 #define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \
39                         (PY_MINOR_VERSION << 16) | \
40                         (PY_MICRO_VERSION <<  8) | \
41                         (PY_RELEASE_LEVEL <<  4) | \
42                         (PY_RELEASE_SERIAL << 0))