【Python】経過時間をhh:mm:ssフォーマットで表示する

Deep Learningの学習工程のように、処理時間が長い場合に、定期的に下図のようにログを表示したかったのですが、timeモジュールのtime()関数で得られた秒数の差を 時:分:秒hh:mm:ss のフォーマットで表示する方法がみつからない。。

deletetimeモジュールを使うと、近いところまでは出来るのですが、時の部分が1桁になり、細かい調整ができません。。

import datetime
print(datetime.timedelta(seconds=12345))
# 3:25:45

細かい事を気にしなければdatetimeを使うのも良いかと思いますが、結局、秒数を hh:mm:ssフォーマットの文字列を返す関数を作ってみました。

def elapsed_time_str(seconds):
    """秒をhh:mm:ss形式の文字列で返す

    Parameters
    ----------
    seconds : float
        表示する秒数

    Returns
    -------
    str
        hh:mm:ss形式の文字列
    """
    seconds = int(seconds + 0.5)    # 秒数を四捨五入
    h = seconds // 3600             # 時の取得
    m = (seconds - h * 3600) // 60  # 分の取得
    s = seconds - h * 3600 - m * 60 # 秒の取得

    return f"{h:02}:{m:02}:{s:02}"  # hh:mm:ss形式の文字列で返す

使い方は、こんな感じです。

start = time.time()
time.sleep(3)
print(elapsed_time_str(time.time() - start))
# 00:00:03

print(elapsed_time_str(12345))
# 03:25:45

Pythonプログラムのexe化

Pythonで作ったプログラム(*.pyファイル)は、Pythonの実行環境と、使用したモジュールがインストールされた環境でないと実行できないため、他のPCでプログラムを実行するのが面倒だったりもします。

PyInstallerというのを使うと、Pythonプログラムをexeにして実行することが可能になります。

私自身は、普段からVisual Studio2019を使って開発しているので、Visual StudioからPyInstallerを使う方法を紹介します。(おそらくVisual Studio2017以降であれば同様の操作で出来ると思います。)

Python環境の作成

Visual StudioのソリューションエクスプローラーPython環境を右クリックし、環境を追加をクリックします。

表示された画面の仮想環境を選択し、名前の部分に適当な名前を付け(今回はexeにしました)、ベースインタープリターの部分で、もともと使っていたPythonの環境(バージョン)を選択し、右下の作成をクリックします。

すると、今回作成した環境(exe)が追加されます。

ただし、パッケージ(PyPI)の部分を見ると、必要なモジュールが何もインストールされていない状態になります。

今回の例では、exe化しようとしているPythonファイル(*.py)は、pillowとnumpyを使用するため、別途、作成したPython環境(exe)に必要なモジュールをインストールする必要があります。

モジュールのインストールはPyPIとインストールされたパッケージの検索の部分に必要なモジュール名を入力すると、次のコマンドを実行する:pip install Pillow が表示されるので、この部分をクリックして、モジュールをインストールします。

各自、必要なモジュールは異なりますので、この状態で、Pythonのプログラムが実行できるか?確認しておいてください。

PyInstallerのインストール

exe化するためのPyInstallerも他のモジュールと同様にインストールします。

PyPIとインストールされたパッケージの検索の部分にpyinstallerと入力し、次のコマンドを実行する:pip install pyinstaller が表示されるので、この部分をクリックして、PyInstallerをインストールします。

私の場合、最終的に、このよう↓になります。

exe化の実行

PyInstallerを使ってexe化するには、コマンドプロンプトでコマンドを入力する必要があるので、コマンドプロンプトを表示します。

プロジェクトの名前の部分を右クリックし、表示されたメニューのここでコマンドプロントを開くをクリックします。

すると、プロジェクトのフォルダがコマンドプロンプト上に表示されます。

ここに、以下のコマンドを入力します。

pyinstaller [pyファイル名]

私の場合は以下のようにしました。

このコマンドを実行すると dist というフォルダが作成されます。

distフォルダの中にさらにプロジェクト名のフォルダが作成され、さらに、この中に目的とするexeファイルが作成されています。

他のPCでexeファイルを実行するには、exeファイルと同一階層にあるファイルすべてが必要になります。

ファイルがいくつも出来てしまうのは、少々扱いが面倒なので、必要なファイルも含めてexeファイル一つにすることもonefileオプションを設定することで可能です。

pyinstaller [pyファイル名] --onefile

また、プログラム起動時に表示されるコマンドプロンプトのウィンドウ↓

を表示させたくない場合は、windowedオプションを指定します。

pyinstaller [pyファイル名] --onefile --windowed 

私の場合の例↓

onefileオプションを使うと distフォルダ内にexeファイルが一つだけ作成されるので、このexeファイルを別のPCに持っていくだけで、Pythonや各種モジュールをインストールすることなく、実行することができます。

ただし、使用するモジュールからさらにdllを参照している場合などは、dllのインストールが必要になるかも?しれません。

参考

https://pyinstaller.readthedocs.io/en/stable/usage.html

【Python】ファイル、ディレクトリの存在確認

ファイル、ディレクトリの存在を確認するには、osモジュールの isfile, isdir, existsを用います。

isfile ファイルの存在の確認
isdir ディレクトリの存在の確認
exists ファイル もしくは ディレクトリの存在の確認
(ファイル、ディレクトリの区別なく存在確認します)

 

(サンプル)

カレントディレクトリ直下に \images\Porrots.bmp というファイルがある場合の例です。

import os

# ファイルが存在するか?
exist = os.path.isfile("images/Parrots.bmp")
print("ファイルの存在: ", exist)
exist = os.path.isfile("images")
print("ファイルの存在: ", exist)

# ディレクトリが存在するか?
exist = os.path.isdir("images/Parrots.bmp")
print("ディレクトリの存在: ", exist)
exist = os.path.isdir("images")
print("ディレクトリの存在: ", exist)

# ファイルもしくはディレクトリが存在するか?
exist = os.path.exists("images/Parrots.bmp")
print("ファイルもしくはディレクトリの存在: " , exist)
exist = os.path.exists("images")
print("ファイルもしくはディレクトリの存在: " , exist)

(実行結果)

 

注意点

ファイル名を相対パスで指定した場合、カレントディレクトリが移動しているとファイル存在の結果が意図した結果にならない場合があります。

カレントディレクトリを取得するには、osモジュールのgetcwd()メソッドを用います。

(参考)

【Python/os】カレントディレクトリの取得/設定

【Python】enumerate()関数で配列の要素とインデックス番号を取得

Pythonで配列の各要素をfor文で取得する場合は、以下のようにします。

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for c in colors:
    print(c)

(実行結果)

ここに、インデックス番号付きで各要素をする場合は

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

i = 0
for c in colors:
    print(i, c)
    i += 1

(実行結果)

とも書けますが、Pythonのenumerate()関数を使うと

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for i, c in enumerate(colors):
    print(i, c)

(実行結果)

となります。

さらに開始値を0以外にしたい場合は、enumerate()関数の引数に開始値を追加し、

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for i, c in enumerate(colors, 11):
    print(i, c)

(実行結果)

とします。

【Python】特殊メソッド

Python以外でクラスを使ったプログラムを作成すると、クラスをインスタンスした時にはコンストラクタが呼ばれ、クラスオブジェクトを解放した時にはデストラクタが呼ばれます。

コンストラクタやデストラクタのように、ある特定の操作をクラスオブジェクトに対して行った時に呼ばれるメソッドをPythonでは特殊メソッド(Special Method)といいます。

Pythonではインスタンスした時や解放した時以外にも様々な特殊メソッドがあります。

(参考)

https://docs.python.org/ja/3/reference/datamodel.html?highlight=__init__#special-method-names

特殊メソッドはアンダーバー2つ(__)で前後が挟まれたメソッド名となります。

 

Deep Learningのプログラムでは比較的この特殊メソッドが使われるので、実際に使った事のある特殊メソッドを紹介します。

__init__(self [, …])

コンストラクタ

クラスがインスタンスされた時に呼ばれます。

__del__(self)

デストラクタ

del object のように、クラスが解放される時に呼ばれます。

ただし、呼ばれない場合もあります。

どちらかというと、挙動はファイナライザに近いです。

__call__(self [, …])

object(a, b, c)のように、クラスオブジェクトに引き数を追加し、クラスオブジェクトをメソッドのように呼び出します。

__len__(self)

len(object)のようにした時に、要素数(int型)を返します。

何の要素数か?は特に規定はなくユーザー次第となります。

__getitem__(self, key)

object[1]のように、クラスオブジェクトに角カッコ付きで配列のように呼び出した時に要素を返します。

__setitem__(self, key, value)

object[1] = 3のように、クラスオブジェクトに角カッコ付きで配列のように、要素を設定します。

__delitem__(self, key)

del object[key] のようにクラスオブジェクトに角カッコ付きで配列の削除のように呼び出した時に要素を削除します。

サンプル

y = a0 + a1*x + a2*x^2+ a3*x^3 +… となるようなn次関数の係数をコンストラクタで設定し、xの値を__call__メソッドで呼び出し、yの値を取得するサンプルです。

class TestClass:
    '''
    y = a0 + a1*x + a2*x^2+ a3*x^3 +・・・の計算
    '''
    def __init__(self, a):
        ''' コンストラクタ '''
        print("__init__")
        self.coeff = a

    def __del__(self):
        ''' デストラクタ '''
        print("__del__")

    def __call__(self, x):
        ''' 呼び出し可能オブジェクト '''
        print("__call__")

        sum = 0
        for i in range(len(self.coeff)):
            sum += self.coeff[i] * x**i

        return sum

    def __len__(self):
        ''' 要素数 '''
        print("__len__")
        return len(self.coeff)

    def __getitem__(self, index):
        ''' 指定した番号の要素取得 '''
        print("__getitem__")
        return self.coeff[index]

    def __setitem__(self, index, value):
        ''' 指定した番号の要素設定 '''
        print("__setitem__")
        self.coeff[index] = value

    def __delitem__(self, index):
        ''' 指定した番号の要素削除 '''
        print("__delitem__")
        del self.coeff[index]

#------------------------------------------------------

# クラスのインスタンス(__init__メソッドの呼び出し)
object = TestClass([2, 1.5, 3]) # y = 2 + 1.5*x + 3*x**2

# __call__メソッドの呼び出し
print(object(3.5))

# 要素数(__len__メソッドの呼び出し)
print(len(object))

# 要素の取得(__getitem__メソッドの呼び出し)
print(object[1])

# 要素の設定(__setitem__メソッドの呼び出し)
object[1] = 0.5
print(object[1])

# 要素の削除(__delitem__メソッドの呼び出し)
del object[2]
print(len(object))

# クラスの解放
del object

(実行結果)

まとめ

個人的には特殊メソッドはコンストラクタ以外は、あまり使う事はないのですが、例えば画像処理で特殊メソッドを駆使するとすると、ガウシアンフィルタのような畳み込みフィルタでは、コンストラクタでカーネルの係数を設定し、__call__メソッドで画像データを引き数で渡して、フィルタ後の画像データを取得するような使い方ができると思います。

特殊メソッドの呼び出され方は決まっていますが、実際にどのようにつかうか?はユーザー次第なので、うまく使えば、キレイなコードを書く事ができると思います。

【Python】変数がNoneかどうか確認する方法

OpenCVで画像ファイルを開く場合では、ファイルがみつからない、日本語パスのためファイルが読み込めないなどのエラーが起きやすいため、画像の変数がNoneかどうかエラーチェックをしたくなります。

そのため、エラーチェックをしたプログラムを書いてみます。

(ダメな例)

import cv2

# OpenCVで画像ファイルを開く
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED)

if img == None:
    print("Load Error")
else:
    cv2.imshow("Image", img)
    cv2.waitKey(0)

このプログラムは一見良さそうで、実際に img == None のときは、正しく動作します。

しかしながら、 img != None のとき(画像ファイルが正しく読み込めたとき)は以下のような例外が発生します。

The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

例外が発生しないようにするには、 == を使うのではなく、 is を使います。

import cv2

# OpenCVで画像ファイルを開く
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED)

if img is None:
    print("Load Error")
else:
    cv2.imshow("Image", img)
    cv2.waitKey(0)

他にも

if img != None:

としたい場合は

if img is not None:

のように != ではなく、 is not を使います。

【Python】指定フォルダ内のファイル、フォルダ一覧を取得

フォルダに格納された画像ファイルの一覧を取得する場合など、フォルダのパスを指定してファイルの一覧を取得したい場合があります。

その場合に、Pythonでは主に3通りの方法があります。

  • glob.glob
    検索条件を指定してファイル、フォルダ一覧を取得
  • os.listdir
    フォルダ内のファイル、フォルダ一覧を取得
  • os.scandir
    フォルダ内のファイル、フォルダ一覧をファイルか?フォルダか?の属性付きで取得

 

試しに以下のようなファイル、フォルダ構成の時に、どのようにファイル、フォルダを取得できるのか?をみていきたいと思います。

└─images
    ├─annotation.csv
    ├─0
    │ ├─img0001.bmp
    │ ├─img0001.png
    │ ├─img0002.png
    │ └─img0003.png
    ├─1
    │ ├─img0101.png
    │ ├─img0102.png
    │ └─img0103.png
    └─2
      ├─img0201.png
      ├─img0202.png
      └─img0203.png

glob.glob

指定したフォルダ内において、検索条件を指定してファイル、フォルダ一覧を取得。

最も使いやすいと思います。

(サンプル)

import glob

files = glob.glob("./images/*")
print(files)
# ['./images\\0', './images\\1', './images\\2', './images\\annotation.csv']

files = glob.glob("./images/*.*")
print(files)
# ['./images\\annotation.csv']

files = glob.glob("./images/0/*.png")
print(files)
# ['./images/0\\img0001.png', './images/0\\img0002.png', './images/0\\img0003.png']

files = glob.glob("./images/**", recursive=True)
print("recursive", files)
# ['./images\\', './images\\0', './images\\0\\img0001.bmp', './images\\0\\img0001.png', './images\\0\\img0002.png', './images\\0\\img0003.png', './images\\1', './images\\1\\img0101.png', './images\\1\\img0102.png', './images\\1\\img0103.png', './images\\2', './images\\2\\img0201.png', './images\\2\\img0202.png', './images\\2\\img0203.png', './images\\annotation.csv']# 

検索条件に * を指定すると、フォルダ内のファイル、フォルダ全てを取得します。

検索条件に *.* を指定すると、フォルダ内のファイルを取得します。ただし、フォルダ名に . が含まれる場合は、そのフォルダも取得します。

検索条件に *.png のように指定すると、指定した拡張子のファイルを取得します。

検索条件に ** を指定し、さらに、recursive=True と指定すると、指定したフォルダ以下(子のフォルダ内を含む)のファイル、フォルダ全てを取得します。

詳細はこちら↓のページを参照ください。

https://docs.python.org/ja/3/library/glob.html?highlight=glob#glob.glob

os.listdir

指定したフォルダ内のファイル、フォルダを取得します。

(サンプル)

import os
files = os.listdir("./images")
print(files)
# ['0', '1', '2', 'annotation.csv']

files = os.listdir("./images/0")
print(files)
# ['img0001.bmp', 'img0001.png', 'img0002.png', 'img0003.png']

os.listdirではファイル、フォルダの区別なく、指定したフォルダ内のファイル、フォルダの一覧を取得します。

取得した一覧からファイルか?フォルダか?を判断するにはos.path.isfile()メソッドos.path.isdir()メソッドを使って以下のように行うことも可能です。

import os

files = os.listdir("./images")

for f in files:
    path = os.path.join("./images", f)
    if os.path.isfile(path):
        # ファイルの場合
        print("[file  ]", f)
    if os.path.isdir(path):
        # ファイルの場合
        print("[folder]", f)

# [Dir ] 0
# [Dir ] 1
# [Dir ] 2
# [File] annotation.csv

詳細はこちら↓のページを参照ください。

https://docs.python.org/ja/3/library/os.html?highlight=os%20listdir#os.listdir

os.scandir

指定したフォルダ内のファイル、フォルダをファイルか?フォルダか?の属性付きで取得します。

os.listdirではファイル、フォルダの一覧を取得後にファイルか?フォルダか?を判断しましたが、os.scandirでは、取得時に属性付きで取得します。

(サンプル)

import os

with os.scandir("./images") as it:
    for entry in it:
        if entry.is_file():
            print("[file   ]", entry.name)
        elif entry.is_dir():
            print("[folder ]", entry.name)

# [Dir ] 0
# [Dir ] 1
# [Dir ] 2
# [File] annotation.csv

あまり使用する機会が少ないのですが、フォルダ構成のまま、ファイルを取得した場合など、再帰的に呼び出すとフォルダ構成を取得できると思います。

詳細はこちら↓のページを参照ください。

https://docs.python.org/ja/3/library/os.html?highlight=os%20listdir#os.scandir

【Python】文字列の大文字、小文字変換

文字列を大文字に変換するには upper()メソッド
文字列を小文字に変換するには lower()メソッドを用います。

このupper()、lower()を使ったサンプルは以下の通りです。

# 元の文字列
str = 'Imaging Solution'
print(str)

# ----------------
# 大文字に変換
temp = str.upper()
print(temp)
# IMAGING SOLUTION

# ----------------
# 小文字に変換
temp = str.lower()
print(temp)
# imaging solution

実行結果

【Python】画像データがNumPyかPillowか調べる方法

Pythonで画像処理をしていると、画像データの型(クラス)は、OpenCVを使っているとNumPyだし、Tkinterで画像を表示しようとすると、Pillowを使ったりもするので、どうしても画像データがNumPyとPillowが混在しがちです。

そこで、画像データがNumPyなのか?Pillowなのか?を調べる方法の紹介です。

画像データに限らず、インスタンスしたクラスのオブジェクトが、どのクラスなのかを調べるにはisinstance関数を用います。

ininstance関数の書式は以下の通りです。

ininstance(クラスオブジェクト, クラス)

クラスオブジェクトが指定したクラスと一致している場合はTrueが、異なる場合はFalseが返ります。

このininstance関数を使って、画像データがNumPyなのか?Pillowなのか?を調べる関数の例を以下に示します。

def check_image_data(image):
    '''画像データがNumPyか、Pillowかを調べる'''
    if isinstance(image, np.ndarray):
        print("NumPy Image")
    elif isinstance(image, Image.Image):
        print("Pillow Image")

この関数を使って、実際に画像データがNumPyかPillowかを調べるサンプルは以下の通りです。

from PIL import Image
import numpy as np

def check_image_data(image):
    '''画像データがNumPyか、Pillowかを調べる'''
    if isinstance(image, np.ndarray):
        print("NumPy Image")
    elif isinstance(image, Image.Image):
        print("Pillow Image")

# Pillowの画像データ
pillow_image = Image.open("Mandrill.bmp")
check_image_data(pillow_image)

# NumPyの画像データ
numpy_image = np.asarray(pillow_image)
check_image_data(numpy_image)

実行結果

 

型を調べるだけならtype関数を使うこともできます。

(例)

print(type(numpy_image))
# <class 'numpy.ndarray'>
print(type(pillow_image))
# <class 'PIL.BmpImagePlugin.BmpImageFile'>

上記のコメント部分がtype関数を使って型を表示した結果になりますが、NumPyの型は‘numpy.ndarray’と表示されているので、まだ分かり易いのですが、Pillowの型は、’PIL.Image.Image’と表示されるのを期待しているのですが、‘PIL.BmpImagePlugin.BmpImageFile’と表示されてしまいます。

これは、bmpファイルからPillowの画像データを開いたためで、別のjpegファイルから開くと別の型が表示されます。

そのため、型を調べる、表示するだけなら type関数、型を判断するならisinstance関数という使い分けが良さそうです。

関連記事

【Python】画像データ(NumPy,Pillow(PIL))の相互変換

【Python/os】パスからファイル名、拡張子、フォルダ名などを取得する

ファイルパスからファイル名、拡張子、フォルダ名などを取得するには、os.pathモジュールを用います。

まずは、サンプルを参照ください。

import os

filepath = r"C:\temp\Image.bmp"

# ファイル名 os.path.basename()
print(os.path.basename(filepath))       # 'Image.bmp'

# フォルダ名 os.path.dirname()
print(os.path.dirname(filepath))        # 'C:\temp'

# 拡張子の取得 os.path.splitext()
print(os.path.splitext(filepath)[1])    # '.bmp'

# 拡張子なしのパス os.path.splitext()
print(os.path.splitext(filepath)[0])    # 'C:\temp\Image'

# 拡張子なしのファイル名 os.path.basename(), os.path.splitext()
print(os.path.splitext(os.path.basename(filepath))[0])    # 'Image'

# ルートディレクトリ os.path.splitdrive()
print(os.path.splitdrive(filepath)[0])  # 'C:'

実行結果

 

使用した関数の説明は以下の通りです。

os.path.basename(path)

パス名(path)から最後の’\’以降のファイル名を返します。

(例)

入力path 戻り値
C:\temp\Images\Image01.bmp Image01.bmp
C:\temp\Images Images

os.path.dirname(path)

パス名(path)のディレクトリ名を返します。

(例)

入力path 戻り値
C:\temp\Images\Image01.bmp C:\temp\Images
C:\temp\Images C:\temp

os.path.splitext(path)

パス名(path)を (拡張子以外, 拡張子)のタプルを返します。

(例)

入力path 戻り値
C:\temp\Images\Image01.bmp (‘C:\\temp\\Images\\Image01’, ‘.bmp’)
C:\temp\Images (‘C:\\temp\\Images’, ”)

os.path.splitdrive(path)

パス名(path)を (ルートディレクトリ, それ以外)のタプルを返します。

(例)

入力path 戻り値
C:\temp\Images\Image01.bmp (‘C:’, ‘\\temp\\Images\\Image01.bmp’)
C:\temp\Images (‘C:’, ‘\\temp\\Images’)

参考

https://docs.python.org/ja/3/library/os.path.html

【Python】リスト(配列)の繰り返しの注意点

Pythonのlistで同じ要素を繰り返して書く場合は、リストの掛け算のように

data_list = [1, 2, 3] * 5
print(data_list)

とすると、

のようにリストの要素を繰り返したリストを取得することができます。

ただ、ここで注意したいのが、各要素のオブジェクト(メモリ)を繰り返してリストが生成されています。

試しに各要素のIDも繰り返されています。

つまり、同じメモリの値が繰り返されている事になります。

そのため、例えば、リストのリスト(二次元のリスト)を作成し、1つの要素だけを変更してみると、下図のように他の要素まで変更されてしまいます。

しかし、一見同じように一次元のリストの繰り返しでは、他の要素は変更されません。

この差は何なのか?というと、Pythonの語彙力がなくてうまく説明できないのですが、値を代入した時に変数のIDが変わるか?変わらないか?の違いによって、差が出ます。

例えば、変数に値を代入すると、IDの値も変わります。

しかし、リストの要素に値を代入しても、リストの変数のIDは変わりません。

こういう事をなんと言うのか???

 

という事で、リストやクラスオブジェクトを * を使ってリストの繰り返しを作る場合は、メモリも同じメモリが繰り返されている事に注意しておかないと、1つの要素を変更したときに他の要素も変更されてしまうので、気を付けましょう!

 

と、今日、この症状のバグにハマっていたので、戒めでこの記事を書いています。

【Python】処理時間の計測

処理時間の計測には、timeモジュールのtime()関数 もしくは perf_counter()関数を時間計測する2か所で実行し、取得した値の差を計算することで、処理時間(秒単位)が取得できます。

 

サンプルプログラム

import time

print("time")
for j in range(5):
    start = time.time()
    time.sleep(1)
    print(time.time() - start)

print("perf_counter")
for j in range(5):
    start = time.perf_counter()
    time.sleep(1)
    print(time.perf_counter() - start)

実行結果

 

time()関数 と perf_counter()関数 とでは、perf_counter()関数の方が高精度らしいのですが、上記のプログラムでは、差がよく分からず。。

注意点

Visual Studio や Visual Studio Codeを使っている場合、デバッグの開始デバッグなしで開始の2種類の実行方法があります。

(Visual Studioの場合)

(Visual Studio Codeの場合)

 

デバッグのあり/なしで処理時間に大きな差が出るので、処理時間を計測する場合は、デバッグなしで実行を選択して実行してください。

 

例えば、以下のようなプログラムを実行し、処理時間を比較すると、

import time

sum = 0
start = time.perf_counter()

for i in range(10000000):
    sum += 1
    
print(time.perf_counter() - start)

処理時間(秒)

デバッグの開始 デバッグなしで実行
Visual Studio 5.0749325 0.8275141
Visual Studio Code 1.6109771 0.7664662999999999

 

Pythonはビルドするわけでは無いので、デバッグあり/なし は処理時間に関係ないと思っていたのですが、特にVisual Studioでは処理時間が大きく異なるので、注意が必要ですね。

【Python】rangeの構文(開始,終了,ステップ数)

Pythonを勉強して、for文を覚えると何となくrangeを使っていましたが、rangeの構文をまとめておきたいと思います。

 

終了の値を指定する方法

range(終了の値未満)

実行結果

開始と終了の値を指定する方法

range(開始の値以上, 終了の値未満)

実行結果

開始と終了の値、ステップ数を指定する方法

range(開始の値以上, 終了の値未満, ステップ数)

実行結果

 

※rangeの値には整数のみ設定可能です。

【Python/PyLint】Visual Studioでエラー、警告の確認

Pythonでは、基本的にビルドしないので、実行するまでエラーが分からないのですが、Visual StudioのPythonプロジェクトからPyLintというエラーチェックツールが使えるようになっており、エラー、警告を確認することができます。

例えば、以下のようなダメダメコード

import numpy as np

flag = False

flag == True

a = a + 1;

if flag == True:
    print("flag:True")
else:
    print("flag:False")

このエラーを確認するには、プロジェクトの右ボタン→Python→PyLintの実行 をクリックします。

初めてPyLintを実行する場合は、以下のようにPyLintをインストールするか?を聞かれるので、足りないパッケージをインストールしてからコマンドを実行しますをクリックして、PyLintをインストールします。

すると、以下のようなメッセージが表示されるので、今すぐ昇格をクリックします。

これで、PyLintがインストールされ、PyLintが実行されます。

最初に示したコードでのエラーの解析結果は以下のようになります。

エラーが1つ、警告が3つ、メッセージが9つ。

内容を見てみると、

  • エラー Using variable ‘a’ before assignment [E:used-before-assignment]
    変数 a が定義される前(値が代入される前)に変数を参照している
  • 警告 Unused numpy imported as np [W:unused-import] 
    numpyのインポートは未使用
  • 警告 Statement seems to have no effect [W:pointless-statement] 
    このコードは意味がなさそう
  • 警告 Unnecessary semicolon [W:unnecessary-semicolon]
    セミコロンは必要ありません

となります。

このエラーと警告の分類ですが、エラーに関しては修正すべき内容がほとんど、警告に関しては実行する分には無視できるかもしれない内容ですが、

flag == True

の部分が

flag = True

を意図していた場合は危険な警告なので、警告に関してもできるだけ修正しておいた方が良さそうです。

エラーコードに関しては、こちら↓が参考になると思います。

http://pylint-messages.wikidot.com/all-codes

Visual StudioのPython環境の切り替え変更

Pythonはインストールした環境ごとに使用できるバージョンやモジュール(パッケージ)を切り替えることができます。

Visual Studioでは、AnacondaやPythonのインストーラなどでインストールした環境の一覧が表示されています。このPython環境を切り替える方法を紹介します。

新規プロジェクトで使用するPython環境の変更方法

新規プロジェクトで使用するPython環境を変更しるには、変更したいPython環境を選択し、概要と表示されている状態で、その下のこれを新しいプロジェクトに対する規定の環境にするをクリックします。

すると、選択したPython環境の文字が太字に切り替わり、次にプロジェクトを作成する時のPython環境が切り替わります。

既存プロジェクトのPython環境の変更方法

Python環境に グローバルデフォルト の環境を使用している場合、前項のようにこれを新しいプロジェクトに対する規定の環境にするをクリックすることで、Python環境を切り替える事ができます。

(変更後)Python3.6からPython3.7へ変更後

Python環境がグローバルデフォルトでない場合、プロジェクトを右クリックし、プロパティを選択します。

表示されたウィンドウの全般インタープリターの中から、変更したいPython環境を選択する事で、Python環境を切り替える事ができます。

ただし、インタープリターの部分で選択を変更した直後では、Python環境の表示が切り替わらないため、どこか関係のないウィンドウを選択し、ウィンドウ表示を切り替える事で、Python環境の表示が切り替わるようになります。