はじめに
今回でProcessing周りの記事を書くのも3回目1 2となりました。
QGISのProcessing便利ですね。QGISのバージョンが上がるにつれて、アルゴリズムも増え、UIの改善も進み、どんどん使いやすくなっているように感じます。
私自身ものすごくProcessingのお世話になっていて、ベクタ・ラスタデータを使って何かしようと思った時や、相談を受けて支援をしようとしたときには、真っ先にProcessingの中の機能で解決できないか探すクセがついています。そして、大抵見つかり、解決できない場合もあるにせよ、何かしら解決の糸口になることが多いです。
さて、今回はProcessingというよりは、Processingスクリプトを書くときのPythonについて、思ったことを書こうと思います。
また、今回の記事を書くにあたって、執筆時点(2020/12/16)で、LTSとなっているQGIS3.10
を対象としています。
Pythonで型を付ける
Pythonは動的型付け言語ですので、コードを書くときに型を意識することはあまりないと思います。ただ、Python3.5でPEP4843が実装されたことによって、Python3.5以降をターゲットに書いたPythonコードには、型を記述できるようになっています。
def sum(a: int, b: int) -> int:
return a + b
class Point2D:
def __init__(self, x: float, y: float) -> None:
self.x: float = x
self.y: float = y
p = Point2D(0.0, 0.0)
def sum(a, b):
return a + b
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point2D(0.0, 0.0)
どうでしょうか。
私的な感想になってしまいますが、型を書いたコードのほうが、型を書かないコードよりもsum
という関数を呼んだときの戻り値が整数であることや、Point2D
クラスのx, y属性は小数であることが、パッと見ただけでもわかりやすいと思います。
QGIS3.10に組み込まれているPythonのバージョンは3.7.3
なので、このような型が書いてあるPythonコードを実行することができます。
Processingで型を付ける
では、Pythonコードに型が記述できるようになったことで、Processingがどうなるかというと、Processingアルゴリズムを実行した結果がベクタレイヤなのかラスタレイヤなのか把握しやすくなります。
例えば、Pythonコードの中でProcessingのアルゴリズムを実行しようとすると、以下のような感じになります。
from typing import Dict
# インターセクトの実行例
params: Dict[str, Any] = { ... }
interect_layer: QgsVectorLayer = processing.run("native:intersection", params)['OUTPUT']
# ラスタ計算機の実行例
params: Dict[str, Any] = { ... }
calc_layer: QgsRasterLayer = processing.run("qgis:rastercalculator", params)['OUTPUT']
# インターセクトの実行例
params = { ... }
intersect_layer = processing.run("native:intersection", params)['OUTPUT']
# ラスタ計算機の実行例
params = { ... }
calc_layer = processing.run("qgis:rastercalculator", params)['OUTPUT']
どうでしょうか。
Processingアルゴリズムを実行する場合、processing.run()
に、実行したいアルゴリズム名と対応するパラメータを引数として渡せばよいので、汎用的に書ける反面、処理結果がベクタレイヤなのかラスタレイヤなのか、ぱっと見よくわからないの状態になっているように思います。これに対して、受け取った結果を代入する変数にQgsVectorLayer
やQgsRasterLayer
といった型を書いておくことによって、処理結果を把握しやすくなっているのではないでしょうか。
おわりに
型をスクリプトの中に書くことによって、従来よりもコードの記述量が多くなってしまうのは確かですが、やはりコードというのは書く時間よりも読む時間の方が長いことを考えると、振り返った時に何をやっているのか、少しでも把握しやすくあるべきだと思います。
型を書かなくても特に問題にはならないですが、型を書いた方が後々幸せになれると思うので、どっちでもいいのであれば型を書いたほうがいいと思います。
特に、複雑なProcessingスクリプトを作ろうと思うと、どうしても一つのPythonスクリプトファイルのコード量が多くなる傾向にあります。それを避けようとしたとしても、アルゴリズム自体が細分化され、結局のところprocessing.run()
で呼び出して、処理結果を変数に代入し、次の入力へ...という感じになってしまいます。
あれ?この変数のデータはラスタだっけ?ベクタだっけ?と混乱を減らすためにも、型は書いておきたいですね。