Pythonのリストまとめ

リスト作成

空のリスト作成

mylist = []
print(mylist)
#[]
mylist = list()
print(mylist)
#[]

初期化と同時に要素を追加

mylist = [1, 2, 3, 4, 5]
print(mylist)
#[1, 2, 3, 4, 5]

リストの要素取り出し

特定の位置の要素を取り出す

mylist = [1, 2, 3, 4, 5]
print(mylist[2])
#3

後ろから数えて、特定の位置の要素を取り出す

mylist = [1, 2, 3, 4, 5]
print(mylist[-2])
#4

スライスによるリストの操作

mylist = [1, 2, 3, 4, 5]
print(mylist[2:])
#[3, 4, 5]
print(mylist[2:4])
#[3, 4]
print(mylist[:2])
#[1, 2]
print(mylist[:-2])
#[1, 2, 3]
print(mylist[-2:])
#[4, 5]
print(mylist[1:5:2])
#[2, 4]
print(mylist[::-1])
#[5, 4, 3, 2, 1]

リストの要素追加

リストの末尾に追加

mylist = [1, 2, 3, 4, 5]
mylist.append(6)
print(mylist)
#[1, 2, 3, 4, 5, 6]

リストの任意の位置に追加

mylist = [1, 2, 3, 4, 5]
mylist.insert(2, 2.5)
print(mylist)
#[1, 2, 2.5, 3, 4, 5]

リストの置換

mylist = [1, 2, 3, 4, 5]
mylist[2] = 3
print(mylist)
#[1, 3, 3, 4, 5]

スライスを使用することも可能

mylist = [1, 2, 3, 4, 5]
print(mylist[1:3])
#[2, 3]
mylist[1:3] = [3, 2]
print(mylist)
[1, 3, 2, 4, 5]

リストの要素存在確認

mylist = [1, 2, 3, 4, 5]
print(3 in mylist)
#True
print(6 in mylist)
#False
print(6 not in mylist)
#True

リストの結合

mylist = [1, 2, 3, 4, 5]
mylist.extend([6, 7, 8])
print(mylist)
#[1, 2, 3, 4, 5, 6, 7, 8]
mylist = [1, 2, 3, 4, 5] + [6, 7, 8]
print(mylist)
#[1, 2, 3, 4, 5, 6, 7, 8]
mylist = [1, 2, 3, 4, 5]
mylist += [6, 7, 8]
print(mylist)
#[1, 2, 3, 4, 5, 6, 7, 8]

リストの繰り返し

mylist = [1, 2, 3, 4, 5] * 3
print(mylist)
#[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

リストの要素削除

すべての要素を削除

mylist = [1, 2, 3, 4, 5]
mylist.clear()
print(mylist)
#[]

特定の値を削除

mylist = [1, 2, 3, 4, 5]
mylist.remove(2)
print(mylist)
#[1, 3, 4, 5]

特定の値が存在しない場合はエラーが出力される。

mylist = [1, 2, 3, 4, 5]
mylist.remove(6)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: list.remove(x): x not in list

特定の値が複数存在する場合には、最初の要素が削除される。

mylist = [5, 1, 2, 3, 4, 5]
mylist.remove(5)
print(mylist)
#[1, 2, 3, 4, 5]

特定の値を全て削除するには…

mylist = [5, 1, 2, 3, 4, 5]
while 5 in mylist:
     mylist.remove(5)
print(mylist)
#[1, 2, 3, 4]
mylist = [5, 1, 2, 3, 4, 5]
mylist = [n for n in mylist if n != 5]
print(mylist)
#[1, 2, 3, 4]

指定した位置の要素を削除

mylist = [1, 2, 3, 4, 5]
mylist.pop(2)
print(mylist)
#[1, 2, 4, 5]

最後の要素を削除

mylist = [1, 2, 3, 4, 5]
mylist.pop()
print(mylist)
#[1, 2, 3, 4]

Docker上で、Python + Selenium + Headless Chromeを使用してWEBスクレイピング

Docker上で、Python + Selenium + Headless Chromeを使用してWEBスクレイピングをしていきます。Dockerは、すでにインストール済みであるとします。

Dockerfile

FROM python:3

RUN apt-get update && apt-get install -y unzip

#install google-chrome
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add && \
    echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
    apt-get update && \
    apt-get install -y google-chrome-stable

#install selenium
RUN pip install selenium

#install ChromeDriver
ADD https://chromedriver.storage.googleapis.com/2.45/chromedriver_linux64.zip /opt/chrome/
RUN cd /opt/chrome/ && \
    unzip chromedriver_linux64.zip

ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/chrome

新しいイメージを構築します。

sudo docker build -t python-selenium-chrome .

WEBスクレイピング用のスクリプトを用意します。

test.py

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

def _main():
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    driver = webdriver.Chrome(options=options)

    driver.get('https://www.google.co.jp/')
    search = driver.find_element_by_name('q')
    search.send_keys('Python')
    search.send_keys(Keys.RETURN)

    time.sleep(3)
    driver.save_screenshot('search_results.png')

    driver.quit()

if __name__ == '__main__':
    _main()

コンテナを起動します。

sudo docker run -it --rm -v $(pwd):/root python-selenium-chrome bash

スクリプトを実行します。

cd /root
python test.py 

無事結果が得られました。

docker-seleniumを使っても良いかも…?

docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome:3.141.59-iron

test.py

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import time


def _main():
    driver = webdriver.Remote(
        command_executor='http:/0.0.0.0:4444/wd/hub',
        desired_capabilities=DesiredCapabilities.CHROME)
 
    driver.get('https://www.google.co.jp/')
    search = driver.find_element_by_name('q')
    search.send_keys('Python')
    search.send_keys(Keys.RETURN)
 
    time.sleep(3)
    driver.save_screenshot('search_results.png')
 
    driver.quit()
 
if __name__ == '__main__':
    _main()

Amazon Linux上で、Python + Selenium + Headless Chromeを使用してWEBスクレイピング

Amazon Linux上で、Python + Selenium + Headless Chromeを使用してWEBスクレイピングをしていきます。

前準備

まず、Amazon EC2で「Amazon Linux 2 AMI (HVM), SSD Volume Type – ami-009d6802948d06e52」を立ち上げます。

Chromeをインストールします。

sudo yum -y install https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm

ChromeDriverをインストールします。

wget https://chromedriver.storage.googleapis.com/2.45/chromedriver_linux64.zip
unzip chromedriver_linux64.zip -d bin/

Python3とSeleniumをインストールします。

sudo yum install python3
sudo pip3 install Selenium

スクレイピング

test.py
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

def _main():
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')
    driver = webdriver.Chrome(options=options)

    driver.get('https://www.google.co.jp/')
    search = driver.find_element_by_name('q')
    search.send_keys('Python')
    search.send_keys(Keys.RETURN)

    time.sleep(3)
    driver.save_screenshot('search_results.png')

    driver.quit()

if __name__ == '__main__':
    _main()

Googleで「Python」を検索して、検索結果のスクリーンショットを取ります。

python3 test.py

以下のようにスクリーンショットが取得できました。

日本語の文字化け

ただし、この状態で日本語を検索すると、以下のように文字化けしてしまいます。

search.send_keys('パイソン')

そこで、日本語フォントをインストールします。

sudo yum install ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts

再度実行すると、文字化けすることなく、スクリーンショットを取得できました。

Python: 文章中の単語出現回数をカウントするときに、defaultdictを使うとシンプルに書ける

例として以下の文章内(words)で出現する単語の頻度をカウントします。

words = ‘Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python has a design philosophy that emphasizes code readability, notably using significant whitespace. It provides constructs that enable clear programming on both small and large scales. In July 2018, Van Rossum stepped down as the leader in the language community.’

面倒臭いので 話をシンプルにするため、「,」や「.」、大文字小文字は考えないことにします。
普通に書くとこんな感じでしょうか。

count_word.py

word_count = {}
for word in words.split():
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1
print(word_count)

こっちの方がわかりやすいでしょうか。

word_count = {}
for word in words.split():
    if not word in word_count:
        word_count[word] = 0
    word_count[word] += 1
print(word_count)

いずれにしても、word_countディクショナリに存在しないwordが出てきたら、初期化をしています。
得られる結果は以下の通りです。

python count_word.py 
{'and': 2, 'the': 2, 'code': 1, 'Van': 1, '1991,': 1, 'is': 1, 'both': 1, 'an': 1, 'down': 1, 'as': 1, 'design': 1, 'in': 2, 'readability,': 1, 'It': 1, 'van': 1, 'Python': 2, 'Rossum': 2, 'interpreted,': 1, 'that': 2, 'provides': 1, 'July': 1, 'has': 1, 'leader': 1, 'stepped': 1, 'enable': 1, 'Created': 1, 'philosophy': 1, 'constructs': 1, 'emphasizes': 1, 'general-purpose': 1, 'notably': 1, 'released': 1, 'high-level,': 1, 'significant': 1, 'Guido': 1, 'using': 1, 'by': 1, 'a': 1, 'on': 1, 'language': 1, 'whitespace.': 1, 'clear': 1, 'programming': 2, 'language.': 1, 'large': 1, 'community.': 1, 'In': 1, 'small': 1, '2018,': 1, 'scales.': 1, 'first': 1}

初期化が面倒くさいので、以下のように書きたくなってしまいますが、これではエラーになってしまいます。

word_count = {}
for word in words.split():
    word_count[word] += 1
print(word_count)
python count_word.py 
Traceback (most recent call last):
  File "count_word.py", line 7, in 
    word_count[word] += 1
KeyError: 'Python'

一つ目のword「Python」がword_countディクショナリに無いためです。
そこで、defaultdictの出番です。defaultdictを使用することで、あらかじめ初期値を設定することができます。

from collections import defaultdict
word_count = defaultdict(int)
for word in words.split():
    word_count[word] += 1
print(word_count)

defaultdict(int)としていますが、これは初期値を0にするということです。

python count_word.py 
defaultdict(, {'and': 2, 'the': 2, 'code': 1, 'Van': 1, '1991,': 1, 'is': 1, 'both': 1, 'an': 1, 'down': 1, 'as': 1, 'design': 1, 'in': 2, 'readability,': 1, 'It': 1, 'van': 1, 'Python': 2, 'Rossum': 2, 'interpreted,': 1, 'that': 2, 'provides': 1, 'July': 1, 'has': 1, 'leader': 1, 'stepped': 1, 'enable': 1, 'Created': 1, 'philosophy': 1, 'constructs': 1, 'emphasizes': 1, 'general-purpose': 1, 'notably': 1, 'released': 1, 'high-level,': 1, 'significant': 1, 'Guido': 1, 'using': 1, 'by': 1, 'a': 1, 'on': 1, 'language': 1, 'whitespace.': 1, 'clear': 1, 'programming': 2, 'language.': 1, 'large': 1, 'community.': 1, 'In': 1, 'small': 1, '2018,': 1, 'scales.': 1, 'first': 1})

無事結果が得られました。
defaultdictを使用することで、for文の中身がすっきりしてわかりやすくなったかと思います。
ちなみに、以下のような書き方も良い感じです。(あまり見かけない気がしますが…)

word_count = {}
for word in words.split():
    word_count[word] = word_count.get(word, 0) + 1
print(word_count)

ディクショナリのgetメソッドを使用して、第1引数に取得したい要素のキーを、第2引数にキーが存在しない場合のデフォルト値を指定しています。
今回の場合には、collections.Counterを使用するのもいいですが、先に全部リスト化する必要があるので、長い文章になった場合にはメモリが足りなくなる恐れがあることに注意です。

Python: boto3を使用してAWSのEC2インスタンスを立ち上げる

まずは、最小限のオプションだけで起動してみます。
ec2.py

import boto3

ec2 = boto3.resource('ec2')
instance = ec2.create_instances(
    ImageId="ami-009d6802948d06e52",
    MinCount=1,
    MaxCount=1
)

print(instance)
python ec2.py 
[ec2.Instance(id=‘[インスタンスID]’)]

立ち上がったインスタンスタイプはm1.smallになります。デフォルトのインスタンスタイプがデフォルトでm1.smallになっているためです。
次は、t2.microを指定して起動します。

instance = ec2.create_instances(
    ImageId="ami-009d6802948d06e52",
    MinCount=1,
    MaxCount=1,
    InstanceType="t2.micro"
)

t2.microのインスタンスが立ち上がりました。
ただ、この状態だと、AWS マネジメントコンソールから「接続」を開くと以下のように表示されます。

インスタンスがキーペアに関連付けられていません。
このインスタンスがキーペアに関連付けられていません。キーペアがない場合、有効なユーザー名とパスワードの組み合わせを使用してこのインスタンスにログインする必要があります。

次は、キーペアを指定して起動します。

instance = ec2.create_instances(
    ImageId="ami-009d6802948d06e52",
    MinCount=1,
    MaxCount=1,
    InstanceType="t2.micro",
    KeyName="[キーペア]"
)

これで、ログインできるかと思いきや、以下のエラーが出力されます。

ssh -i "[pemファイル]" ec2-user@ドメイン名
ssh: connect to host [ドメイン名] port 22: Operation timed out

22番ポートが開放されていないようです。
次は、セキュリティグループIDを指定して起動します。

instance = ec2.create_instances(
    ImageId="ami-009d6802948d06e52",
    MinCount=1,
    MaxCount=1,
    InstanceType="t2.micro”,
    KeyName="[キーペア]",
    SecurityGroupIds=["[セキュリティグループID]"]
)

無事ログインできました。

Python: ArgumentParserを使用してコマンドライン引数を取得するときのチートシート

Pythonの実行時にコマンドライン引数を取得したい場合には、Pythonの標準モジュールであるArgumentParserを使用すると便利です。

ArgumentParserのシンプルな使用方法

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg1')
parser.add_argument('arg2')
parser.add_argument('arg3')
args = parser.parse_args()

print(args.arg1, args.arg2, args.arg3)
python test.py -h
usage: test.py [-h] arg1 arg2 arg3

positional arguments:
  arg1
  arg2
  arg3

optional arguments:
  -h, --help  show this help message and exit
python test.py aaa bbb ccc
('aaa', 'bbb', 'ccc')

オプション引数を取りたい場合

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg1')
parser.add_argument('--arg2')
parser.add_argument('-a', '--arg3', default="ccc")
args = parser.parse_args()

print(args.arg1, args.arg2, args.arg3)
python test.py -h
usage: test.py [-h] [--arg2 ARG2] [-a ARG3] arg1

positional arguments:
  arg1

optional arguments:
  -h, --help            show this help message and exit
  --arg2 ARG2
  -a ARG3, --arg3 ARG3
python test.py aaa
('aaa', None, 'ccc')
python test.py aaa --arg2 bbb -a ddd
('aaa', 'bbb', 'ddd')

複数のコマンドライン引数を受け取る

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg1', nargs='*')
parser.add_argument('arg2')
args = parser.parse_args()

print(args.arg1, args.arg2)
python test.py -h
usage: test.py [-h] [arg1 [arg1 ...]] arg2

positional arguments:
  arg1
  arg2

optional arguments:
  -h, --help  show this help message and exit
python test.py aaa bbb ccc ddd
(['aaa', 'bbb', 'ccc'], 'ddd')

コマンドライン引数でファイル名を受け取る

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg1', type=argparse.FileType('r'))
args = parser.parse_args()

print(args.arg1.read())
python test.py aaa
usage: test.py [-h] arg1
test.py: error: argument arg1: can't open 'aaa': [Errno 2] No such file or directory: 'aaa'
python test.py test.txt
[test.txtの中身]

Python: 内包表記のチートシート

リスト内包表記

リスト内の全ての要素を2倍にする

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9]
newlist = [n*2 for n in mylist]
print(newlist)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

リスト内の偶数のみ取り出す

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9]
newlist = [n for n in mylist if n%2==0]
print(newlist)
[2, 4, 6, 8]

リスト内の偶数は”even”、奇数は”odd”とする

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9]
newlist = ["even" if n%2==0 else "odd" for n in mylist]
print(newlist)
['odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

辞書内包表記

辞書の要素を全て2倍にする

mydict = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
newdict = {k:v*2 for k,v in mydict.items()}
print(newdict)
{'a': 2, 'c': 6, 'b': 4, 'e': 10, 'd': 8}

辞書の要素が偶数であるもののみ取り出す

mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9]
newdict = {k:v for k,v in mydict.items() if v%2==0 }
print(newdict)
{'b': 2, 'd': 4}

Python: リスト内の全ての要素を2倍する

シンプルにfor文を使用する方法

mylist = [1,2,3,4,5,6,7,8,9]
newlist = []
for n in mylist:
    newlist.append(n*2)
print(newlist)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

わかりやすいですが、行数が多くなります。

python内包表記を使用した方法

mylist = [1,2,3,4,5,6,7,8,9]
newlist = [n*2 for n in mylist]
print(newest)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

個人的には一番好きです。最もPythonらしい書き方かと思います。

map関数を使用した方法1

def double(n):
     return n*2

mylist = [1,2,3,4,5,6,7,8,9]
newlist = map(double, mylist)
print(newlist)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

Pythonではあまりmap関数は多用しないかと思いますが、他の言語から入ってきた方にはわかりやすいかもしれません。

map関数を使用した方法2(ラムダ式で無名関数を定義する)

mylist = [1,2,3,4,5,6,7,8,9]
newlist = map(lambda x: x*2, mylist)
print(newlist)
[2, 4, 6, 8, 10, 12, 14, 16, 18]

適用する関数の内容がシンプルな場合には、ラムダ式で十分かと思います。

Python入門

Pythonとは

Pythonは、1991年にGuido van Rossum(グイド・ヴァンロッサム)氏により開発されたプログラミング言語です。C言語などのように機械に近い言語を「低級言語」と呼びますが、Pythonは比較的人間が理解しやすい「高級言語」に分類されます。Pythonは高級言語の中でも、特に習得が容易であるため、プログラミング初心者に向いている言語であると言われています。しかしながら、初心者だけが使用するプログラミング言語というわけではありません。Pythonは多くの企業で採用されており、実践的なプログラミング言語でもあります。特にデータ分析やWEBアプリ開発の分野で、よく利用されています。

Pythonを選ぶ理由

学習コストが低い

Pythonは比較的シンプルな文法ですので、学習にかかる時間も少なく済みます。

汎用的である

Pythonは他の言語と比べると多くの用途に利用できます。データ分析の分野に興味があるのであれば、Pythonが第一選択肢になるかと思います。WEBアプリ開発の分野でも多く利用されています。よく比較される言語であるPerlやRubyやPHPの場合、WEBアプリ開発には向いていますが、データ分析を本格的に行うには向いていません。

WEB上に情報が多い

これは、Pythonのユーザー数が多いことに起因します。ユーザー数が多ければ、その分、情報を発信する人が多くなります。

ライブラリが充実

ライブラリとは、よく使用される機能をひとまとまりにしたプログラムです。ライブラリが充実していれば、開発時間を短縮することが可能です。これも、Pythonのユーザー数が多いことに起因します。