Python2.5で動作するプログラムを書く際の留意点まとめ

Python 2.5環境で動かすプログラムを作成する際の留意点のまとめ。
主にPython 2.5で使えない機能(モジュール・ビルドイン機能)と、その対策(代替機能)について。
※本記事で紹介しているのは一部のみで、他にも色々あります


# モジュール
Python 2.5で使用できないモジュール群と代替機能について。

## stringモジュール
stringモジュール自体は2.5でも使用できるが、string.Formatterクラスが使用できない。

[7.1. string — Common string operations — Python 2.7.11 documentation](https://docs.python.org/2.7/library/string.html)

>### 7.1.2. String Formatting
>New in version 2.6.

```
message = "<format>".format(<parames>)
```

というようなformat関数の呼び出しはできない。

### 対策
旧式のformatting方式をつかう。

```py:e.g.
message = "hogehoge %d %s" % (123, "test")
```

## argparseモジュール
[15.4. argparse — Parser for command-line options, arguments and sub-commands — Python 2.7.11 documentation](https://docs.python.org/2.7/library/argparse.html)

>New in version 2.7.

>The argparse module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and argparse will figure out how to parse those out of sys.argv. The argparse module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.

### 対策
#### optparseモジュールを使う
[15.5. optparse — Parser for command line options — Python 2.7.11 documentation](https://docs.python.org/2.7/library/optparse.html)

>New in version 2.3.

>optparse is a more convenient, flexible, and powerful library for parsing command-line options than the old getopt module. optparse uses a more declarative style of command-line parsing: you create an instance of OptionParser, populate it with options, and parse the command line. optparse allows users to specify options in the conventional GNU/POSIX syntax, and additionally generates usage and help messages for you.

optparseはPython 2.5にデフォルトで入っている。argparseと比較すると使いにくい。
argparseとoptparseの差については以下が詳しい。

[argparse vs. optparse — argparse v1.1 documentation](https://argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html)

#### argparseパッケージをインストールする
独立したパッケージとしてargparseがあるため、これをインストールする。
https://pypi.python.org/pypi/argparse

>Compatibility
>
>argparse should work on Python >= 2.3, it was tested on:
>
>- 2.3, 2.4, 2.5, 2.6 and 2.7
>- 3.1, 3.2, 3.3, 3.4

argparseパッケージ自体はPython 2.5もサポートしている。

## multiprocessingモジュール
[16.6. multiprocessing — Process-based “threading” interface — Python 2.7.11 documentation](https://docs.python.org/2.7/library/multiprocessing.html)

>New in version 2.6.

>multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

### 対策
#### threadingモジュールを使う
[16.2. threading — Higher-level threading interface — Python 2.7.11 documentation](https://docs.python.org/2.7/library/threading.html)

>This module constructs higher-level threading interfaces on top of the lower level thread module. See also the mutex and Queue modules.

IO intensiveなプログラムだとthreadingでもマルチスレッド化することは有効。
一方で、CPU intensiveなプログラムだと、threadingはmultiprocessingの代替とならない。
multiprocessingだとマルチスレッド化するとCPU負荷は複数のコアに分散する。
しかし、threadingだと1コアに負荷が集中するため、マルチスレッド化しても効果は薄い。

#### multiprocessingパッケージをインストールする
Python 2.5用にバックポートされたモジュールがある。

https://pypi.python.org/pypi/multiprocessing/

>Backport of the multiprocessing package to Python 2.4 and 2.5

## jsonモジュール
[18.2. json — JSON encoder and decoder — Python 2.7.11 documentation](https://docs.python.org/2.7/library/json.html)

>New in version 2.6.

### 対策
#### simplejsonパッケージをインストールする
https://pypi.python.org/pypi/simplejson/

>simplejson is a simple, fast, complete, correct and extensible JSON <http://json.org> encoder and decoder for Python 2.5+ and Python 3.3+. It is pure Python code with no dependencies, but includes an optional C extension for a serious speed boost.

simplejsonのインターフェースはjsonモジュールと同じ。

## itertoolsモジュール
itertools自体はPython 2.5で使用できるものの、一部関数が2.6以降で追加されている。

[9.7. itertools — Functions creating iterators for efficient looping — Python 2.7.11 documentation](https://docs.python.org/2.7/library/itertools.html)

>New in version 2.3.

>itertools.permutations(iterable[, r])
Return successive r length permutations of elements in the iterable.
New in version 2.6.

>itertools.product(*iterables[, repeat])
Cartesian product of input iterables.
New in version 2.6.

### 対策
特に無し。
これは諦めるしかない？

## collectionsモジュール
`collections.Mapping`が使えない。公式ページを見ても2.5の時点で使えそうにみえるが・・・

[8.3. collections — High-performance container datatypes — Python 2.7.11 documentation](https://docs.python.org/2.7/library/collections.html)

>New in version 2.4.

`isinstance({}, collections.Mapping)`をPython 2.5で実行すると失敗する。
Python 2.7では成功する。

```pycon:Python2.5
# python
Python 2.5.2 (r252:60911, Jan 24 2010, 14:53:14)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import collections
>>> isinstance({}, collections.Mapping)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'Mapping'
>>>
```

```pycon:Python2.7
# python
Python 2.7.3 (default, Jan  2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import collections
>>> isinstance({}, collections.Mapping)
True
>>>
```

## 対策
isinstanceで使用する場合に限っては`isinstance({}, dict)`とするか、isinstanceを使わないことで対応できる。
collections.Mappingを継承するクラスを作りたい場合は諦める。

以下、isinstanceに関する対策。
この問題に直面した人の投稿がある。

[google app engine - Python 2.5 version of this method - Stack Overflow](http://stackoverflow.com/questions/5058039/python-2-5-version-of-this-method)

>I have the below function running fine on python 2.6, but appengine's production environment is 2.5 and it blows up on:
>AttributeError: 'module' object has no attribute 'Mapping'
>Does anyone have a solution for 2.5?

回答では、`isinstance(val, dict)`を使いなさい。
というものと、isinstanceを使うのをやめなさい。という回答がある。
	
>- Try to stop using isinstance! – David Heffernan Feb 20 '11 at 15:59

>- Or get rid of isinstance calls completely, since they are the enemy of duck typing. – Xiong Chiamiov Feb 20 '11 at 17:53

isinstanceはdock typingの敵である、というコメントはどういう意味か。

### dock typingとは
[まつもと直伝 プログラミングのオキテ - まつもと直伝 プログラミングのオキテ 第4回（3）：ITpro](http://itpro.nikkeibp.co.jp/article/COLUMN/20050926/221633/)

>あるオブジェクトがどのクラスに所属するオブジェクトかは一切考慮せず，どのように振る舞うか（どのようなメソッドを持つか）だけに関心を払うのがDuck Typingです。Duck Typingを言い出したのは「達人プログラマ」として知られるDave Thomasです。

実際にDuck Typingをするにはどうすればいいか

>では，動的型の言語でDuck Typingを実践するにはどのような指針に従えばよいのでしょうか。基本的な原則はたった1つ，最低限これだけを覚えておけば大丈夫です。

>●明示的な型チェックを避ける

isinstanceはこれに反しているというわけですね。

### isinstanceを使わないようにする
にはどういうコードを書けばいいか。
具体例を探してみると、あった。

[Error importing 'Mapping' with Python 2.5 · Issue #8 · django-nonrel/django-dbindexer](https://github.com/django-nonrel/django-dbindexer/issues/8)

[Use duck-typing instead of Mapping for recursive settings updating. · django-nonrel/django-dbindexer@d11bdc3](https://github.com/django-nonrel/django-dbindexer/commit/d11bdc3418ff13d4a9d9e9d632b19d3189d6385e)

isinstanceの代わりに try - except で判定している。

## six
最新版ではなく、1.8.0を使用する。
詳細は[Python2.5でsixを使う際の注意点 - Qiita](http://qiita.com/vmmhypervisor/items/e89c4adc104a3d02d048)を参照。

## Voluptuous
[Python2.5でVoluptuousをインストールする - Qiita](http://qiita.com/vmmhypervisor/items/8f08e1221c4213e14460)を参照。


# Pythonビルトイン機能
## withキーワード
↓のようなコードは普通にPython 2.5で実行するとエラーになる。

```python:with_sample.py(NG例)
with open("hoge", "w") as fp:
	fp.write("foo")
```

```console:NG例出力
# python --version
Python 2.5.2
# python with_sample.py
with_sample.py:1: Warning: 'with' will become a reserved keyword in Python 2.6
  File "with_sample.py", line 1
    with open("hoge", "w") as fp:
            ^
SyntaxError: invalid syntax
```

### 対策
`from __future__ import with_statement`をプログラムの先頭に記述する。

```py:with_sample.py
from __future__ import with_statement

with open("hoge", "w") as fp:
	fp.write("foo\n")
```

```console
# python with_sample.py
# cat hoge
foo
```

成功する。

`from __future__ import <feature>`は先のバージョンで標準になった機能を過去バージョンで使用するためのもの。以下はその一覧。

[28.11. __future__ — Future statement definitions — Python 2.7.11 documentation](https://docs.python.org/2.7/library/__future__.html)

feature|optional in|mandatory in|effect
---|---|---|---
nested_scopes	|2.1.0b1	|2.2	|PEP 227: Statically Nested Scopes
generators	|2.2.0a1	|2.3	|PEP 255: Simple Generators
division	|2.2.0a2	|3.0	|PEP 238: Changing the Division Operator
absolute_import	|2.5.0a1	|3.0	|PEP 328: Imports: Multi-Line and Absolute/Relative
with_statement	|2.5.0a1	|2.6	|PEP 343: The “with” Statement
print_function	|2.6.0a2	|3.0	|PEP 3105: Make print a function
unicode_literals	|2.6.0a2	|3.0	|PEP 3112: Bytes literals in Python 3000

## asキーワード
except中にasを使うと失敗する。

```python:except_sample.py(NG例)
try:
	raise ValueError("hoge")
except ValueError as e:
	print e
```

```console:NG例出力
# python --version
Python 2.5.2
# python except_sample.py
except_sample.py:3: Warning: 'as' will become a reserved keyword in Python 2.6
  File "except_sample.py", line 3
    except ValueError as e:
                       ^
SyntaxError: invalid syntax
```

同じプログラムでもPython 2.6以降では動く。

```console:python2.7
# python --version
Python 2.7.3
# python except_sample.py
hoge
```

### 対策
`as`を`,`に置換する。

```python:except_sample.py
try:
	raise ValueError("hoge")
except ValueError, e:
	print e
```

```console
# python --version
Python 2.5.2
# python except_sample.py
hoge
```

ちなみに`import`や`with`キーワードはPython 2.5でも`as`が使える。

```python:as_sample.py
from __future__ import with_statement
import simplejson as json

try:
	raise ValueError("hoge")
except ValueError, e:
	print e

with open("hoge", "r") as fp:
	print fp.read()
```

```console
# python --version
Python 2.5.2
# python as_sample.py
hoge
foo
```

ただし、これをやるとPython 3系では動作しなくなる。
Python 3でも互換性を保つためには以下。

[Python2.5とPython3で互換性を保つための例外処理の書き方 - vmmhypervisor](http://vmmhypervisor.hatenablog.com/entry/2016/01/11/080000)