3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FOSS4GAdvent Calendar 2020

Day 16

QGISのProcessingで実行するPythonスクリプトにも型を付けよう

Last updated at Posted at 2020-12-16

はじめに

今回で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()に、実行したいアルゴリズム名と対応するパラメータを引数として渡せばよいので、汎用的に書ける反面、処理結果がベクタレイヤなのかラスタレイヤなのか、ぱっと見よくわからないの状態になっているように思います。これに対して、受け取った結果を代入する変数にQgsVectorLayerQgsRasterLayerといった型を書いておくことによって、処理結果を把握しやすくなっているのではないでしょうか。

おわりに

型をスクリプトの中に書くことによって、従来よりもコードの記述量が多くなってしまうのは確かですが、やはりコードというのは書く時間よりも読む時間の方が長いことを考えると、振り返った時に何をやっているのか、少しでも把握しやすくあるべきだと思います。
型を書かなくても特に問題にはならないですが、型を書いた方が後々幸せになれると思うので、どっちでもいいのであれば型を書いたほうがいいと思います。

特に、複雑なProcessingスクリプトを作ろうと思うと、どうしても一つのPythonスクリプトファイルのコード量が多くなる傾向にあります。それを避けようとしたとしても、アルゴリズム自体が細分化され、結局のところprocessing.run()で呼び出して、処理結果を変数に代入し、次の入力へ...という感じになってしまいます。

あれ?この変数のデータはラスタだっけ?ベクタだっけ?と混乱を減らすためにも、型は書いておきたいですね。

  1. QGISのprocessingを使ってパンシャープン画像作ってみた

  2. QGISのprocessingでできそうなこと

  3. 日本語訳はこちらが参考になります。
    こんな感じです。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?