- Published on
Python基礎
- Authors
- Name
- Kikusan
- Refs
- コードスタイル
- 構文
- 基本
- ドキュメント
- 文字列
- コメント
- IF
- while for
- リスト
- タプル
- 辞書
- 集合
- 例外処理
- 関数
- クロージャ
- デコレータ
- ラムダ
- ジェネレータ
- 内包表記
- グローバル変数
- オブジェクト指向
- コマンド実行
- コマンドライン引数
- パッケージと配布
- ファイル操作
- 設定を読み書き
- logging
- プログレスバー
- json
Refs
酒井さんのpython講座の内容を自分用にまとめたものです。
コードスタイル
vscodeでは, settings.jsonに "python.linting.flake8Enabled": true で警告表示ができる。
拡張機能のautopep8でオートフォーマットできる。
# import 標準ライブラリ
# import サードパーティ
# import プロジェクト固有
class HumanRobot
def say_hello
is_empty #変数
global GLOBAL_NAME
# 文字列は基本' 場合に応じて"
# 長い文字列はリストにappendしてjoinするとメモリ効率がいい
# インデントは4半角
# 関数の引数には str=s でいいがそれ以外は str = s と半角をいれる
# 関数とクラスの間は 2行(クラス内関数は1行)
def doc_function(params):
"""docs for function
params: docs for params
return: docs for return
"""
return params
# generatorをなるべく使う メモリ削減のため
#def t():
# num = []
# for i in range(10):
# num.append(i)
# return num
def t():
for i in range(10):
yield i
for i in t():
print(i)
# 短い関数はなるべくlambdaを使う
# False 0 '' [] (), {}, set() 以外はTrueなのを使う
x = 1 if y else 2
# 関数の引数ではオブジェクトの初期化をしない
def aaa(not_list=None):
if not_list is None:
not_list = []
pylintを使用してコードをきれいにできる。
pip install pylint
pylint calculation.py
pycharmとvscodeでも警告出してくれるようにできる。
構文
基本
num = 1
name = 'Mike'
is_ok = True
print(name)
print(type(int('1')), type(is_ok))
# 整数
print(17//3)
# 余り
print(17 % 3)
# べき乗
print(5 ** 3)
# 丸め
print(round(3.141, 2))
ドキュメント
import math
# 平方根
math.sqrt(25)
# ドキュメント
help(math)
文字列
print('I don\'t \nknow')
# rは生の文字として扱う
print(r'C:\desktop')
# 複数行 \は空白行を削除してくれる
print(
"""\
line1
line2
"""
)
print('Hi.' * 3 + name)
word = 'python'
# スライス
print(word[-1])
print(word[0:2])
print(word[:3])
word = 'j' + word[1:]
print(len(word))
s = 'My name is Mike. Hi Mike.'
# True or False
print(s.startswith('My'))
# f-stringFormat
x, y, z = 'x', 'y', 'z'
print(f'a is {x}{y}{z}')
# テンプレート
import string
t = string.Template("""
$name, $age
""")
contents = t.substitute(name='Mike', age='19')
print(contents) # Mike, 19
コメント
# comment
# コメントは上がいい
"""
comment
comment
"""
# 複数行
s = 'aaaa' + \
'bbbb'
s = ('aaaa'
+ 'bbbb')
IF
if 10 > 0:
print('true')
elif 10 > 5:
print('elif')
else:
print('else')
# ネストはインデントで
# == 等しい != 等しくない
# and or not(!)
y = [1,2,3]
x = 1
# in演算子 はその中に存在するか ※for in とは役割が異なる
# リストタプルセットはその通り、dictはキーが要素になる
if x in y:
print('in')
if 100 not in y:
print('not in')
# 論理値 True 0以外 'aaa' [1] False 0 '' [] (), {}, set()
# isはオブジェクトが同じものか
is_empty = None
if is_empty is None:
print('None')
while for
# while else: 終了後(breakではいかない)
# break: ループ終了
# continue: 次のループ
count = 0
while count < 5:
print(count)
count += 1
else:
print('done')
count = 0
while True:
if count >= 5:
break
if count == 2:
count +=1
continue
print(count)
count += 1
# input関数でコンソールと対話できる
# while True:
# word = input('Enter:')
# if word == 'ok':
# print('next')
# break
# rangeは(start, end, 間隔)のlistを作る
# _ を変数にするとforの中では使わないことがわかる
for _ in range(2, 10, 3):
print(_)
else:
print('done')
# enumerateはイテレータにindexがついて帰ってくる(タプルみたいenumerateオブジェクト)
for i, fruit in enumerate(['apple', 'banana', 'orange']):
print(i, fruit)
# 0 apple
# 1 banana
# 2 orange
# zipはイテレータをまとめられる (タプルみたいなzipオブジェクト)
# 一番短いイテレータのlen()分帰ってくる
for day, fruit in zip(['Mon', 'Tue', 'Wed'], ['apple', 'banana', 'orange']):
print(day, fruit)
# Mon apple
# Tue banana
# Wed orange
リスト
l = []
l.append('2')
l.insert(0, 1)
l.append([1,2,3])
print(len(l))
print(l[1:3])
print([1, 2, 3] + [4, 5, 6])
if '2' in l:
print(l.index('2'))
print(all([False, 1, 'a'])) # False
print(any[False, 1, 'a']) # True
タプル
t = (1,2,3)
# t[0] = 0 変更できない(appendもできない)
# オブジェクトを入れて中身を変更はできる
t = 1,2,3 # カンマ区切りでタプルと認識されてしまう
print(type(t))
# タプルのアンパッキング
x, y, z = t
print(x, y, z)
x, y = y, x
print(x, y)
辞書
d = {'x': 10, 'y': 20}
print(d['x'])
d['x'] = {'xx': 10, 2: 20}
print(d['x'][2])
# key: value (普通にinを使うとキーを値としてループ)
for k, v in d.items():
print(k, v)
集合
# 重複を禁じる集合
s = set()
s = {1,1,2,2,3,3,4}
s2 = {1,2}
print(s)
print(type(s)) # <class 'set'>
# 差分、論理和、論理積
print(s - s2, s & s2, s | s2) # {3, 4} {1, 2} {1, 2, 3, 4}
例外処理
# 例外処理
def get_error():
l = [1, 2, 3]
i = 5
result = l[i]
return result
try:
result = get_error()
except IndexError as ex:
print(ex)
except Exception as ex:
print(ex)
# elseは正常に抜けると実行
else:
print('done')
# finallyはエラーcatchしなくても実行
finally:
print('fin')
# 独自例外
class UppercaseError(Exception):
pass
def check():
words = ['APPLE', 'orange']
for word in words:
if word.isupper():
raise UppercaseError(word)
try:
check()
except UppercaseError as ex:
print(ex)
関数
def say_something():
print('hi')
say_something()
f = say_something()
f
def what_is_this(color):
"""
what is this function
Parameters
-------------------
param1: explain param1
"""
if color == 'red':
return 'tomato'
else:
return "I don't know"
result = what_is_this('green')
print(result)
# 引数と戻り値は宣言できるけどプログラムは認識しない
def add_num(a: int, b: int) -> int:
return a + b
r = add_num('10', '20')
print(r)
# キーワード引数とデフォルト値
def menu(drink='wine', dessert='fruit'):
print('drink = ' + drink)
print('dessert = ' + dessert)
menu(dessert='ice')
# デフォルト引数には参照渡しするものをいれないほうがいい
# オブジェクトの初期化は関数の中で
# 引数のタプル化
def say_something(word, *args):
print('word = ' + word)
for arg in args:
print(arg)
# say_something('Hi!', 'Mike', 'Nance')
# タプルのアンパッキング
t = ('Mike', 'Nancy')
say_something('Hi!', *t)
# キーワード引数の辞書化
def menu(**kwargs):
for k, v in kwargs.items():
print(k,v)
d = {
'entree': 'beef',
'drink': 'ice coffee'
}
menu(**d)
# タプルは残りの引数、辞書はキーワード引数
def menu(food, *args, **kwargs):
print(food)
print(args)
print(kwargs)
menu('banana', 'apple', 'orange', entree='beef', drink='coffee')
# docstrings
def example_func(param1, param2):
"""
:param param1: int
:param param2: str
:return: True
"""
print(param1)
print(param2)
return True
print(example_func.__doc__)
# 関数内関数
def outer(a, b):
def plus(c, d):
c + d
return c + d
outer(1,2)
クロージャ
# 今実行したくない処理をおいておける
def circle_area_func(pi):
def circle_area(radius):
return pi * radius * radius
return circle_area
ca1 = circle_area_func(3.14)
ca2 = circle_area_func(3)
# caに入っているのはcircle_area関数
print(ca1(10)) # 314.0
print(ca2(10)) # 300
デコレータ
# 関数前後で何かしたい
def print_info(func):
# wrapperに引数を与える
def wrapper(*args, **kwargs):
print(func.__name__)
print(args, kwargs)
# あらかじめfuncに渡した関数に展開する
result = func(*args, **kwargs)
return result
return wrapper
# @関数名で、あらかじめ用意したデコレータを起動できる
# 二つデコレータを重ねると先に書いたほうの中に後に書いたほうが入る
@print_info
def calc_num(a, b, x=2):
return (a + b) * x
r = calc_num(10,20, x=3)
# 起きていること
# 1. f = print_info(add_num)
# 2. r = f(10, 20, * 3)
print(r)
# calc_num
# (10, 20) {'x': 3}
# 90
# *************
# デコレータに引数を与えるとき
# *************
def tag(name):
def _tag(f):
def _wrapper(content):
print('<{}>'.format(name))
r = f(content)
print('</{}>'.format(name))
return r
return _wrapper
return _tag
def f(content):
print(content)
@tag('h3')
def f_deco(content):
print(content)
# デコレータを使わない場合
f = tag('h3')(f)
f('test')
# デコレータを使う場合
f_deco('test')
# <h3>
# test
# </h3>
ラムダ
# ラムダ lambda 引数1, 2...: 戻り値
l = ['Mon', 'tue', 'Wed', 'thu', 'fri', 'Sun']
def change_words(words, func):
for word in words:
print(func(word))
change_words(l, lambda word: word.capitalize())
change_words(l, lambda word: word.lower())
ジェネレータ
returnの代わりにyieldとしたもので、一つずつ返される。リストを使うよりも速かったりする
関数にyieldがあるとgeneratorになる。
内部では__next__() 関数で実装されており、generatorをlistにキャストすると
全てのyieldを要素とするリストが返ってくる。
# 一つ一つ要素を返す
def greeting():
yield 'Good morning'
yield 'Good afternoon'
yield 'Good night'
for x in greeting():
print(x)
# Good morning
# Good afternoon
# Good night
g = greeting()
print(type(g))
print(list(g))
# <class 'generator'>
# ['Good morning', 'Good afternoon', 'Good night']
g = greeting()
print(next(g))
print(next(g))
print(next(g))
# Good morning
# Good afternoon
# Good night
print(list(g))
内包表記
# list内包表記 [iの処理 for i in 配列など if 判定式]
t = (1,2,3,4,5)
t2 = (6,7,8,9,10)
# i にfor i in t if i % 2 == 0を入れていく
r = [i for i in t if i % 2 == 0]
print(r)
r = [i * j for i in t for j in t2]
print(r)
# 辞書内包表記 {キー:値 for i in 配列など}
w = ['mon', 'tue', 'wed']
f = ['coffee', 'milk', 'water']
d = {x: y for x, y in zip(w, f)}
print(d)
# 集合内包表記 {iの処理 for i in 配列など}
s = {i for i in range(10) if i % 2 == 0}
print(s)
# ジェネレータ内包表記 (iの処理 for i in 配列など)
# tupleは tuple(iの処理 for i in 配列など)
def g():
for i in range(10):
yield i
g = (i for i in range(10))
print(type(g))
print(next(g))
グローバル変数
# 変数
animal = 'cat'
def f():
# globalのアニマルを使う宣言
global animal
animal = 'dog' # global宣言していないanimalに入れると、関数の外では'cat'になる
animal2 = 'rubbit'
# locals()はlocal変数が返ってくる
print('local:', locals())
# globalはグローバル変数
# __name__:__main__は実行した関数のとき
print('global:', globals())
def f2():
animal = 'cat'
f()
print(animal) # dog
f2()
print(animal) # dog
オブジェクト指向
# Person Person() Person(object) どれでもいい
class Person(object):
# クラス変数 全てのインスタンスで共有
kind = 'human'
# クラスメソッド
@classmethod
def what_is_your_kind(cls):
return cls.kind
# 静的メソッド(あんまりいみない)
@staticmethod
def about(year):
print(f'human: {year}')
# selfは自分自身、クラスのメソッドには第一引数で与える。勝手に引数になる
# initでコンストラクタ
def __init__(self, name=''):
self.name = name
print(self.name)
# 特殊メソッドは__ __ になっているやつ
def __str__(self):
return('person class')
def say_something(self):
print('hello')
# delはキルされるとき実行(デコンストラクタ)
def __del__(self):
print('Good Bye')
# クラスメソッド実行
print(Person.what_is_your_kind())
# スタティックメソッド実行
print(Person.about(18))
# インスタンス生成 ()がないとinitされない。クラスそのもの
person = Person()
person.say_something()
# __str__で文字列設定
print(person)
del person
# 継承
class Car(object):
def __init__(self, model=None):
self.model = model
def run(self):
print('run')
class ToyotaCar(Car):
def __init__(self, model=None, enable_auto_run=False):
# 親のコンストラクタの呼び出し
super().__init__(model)
# _は外部からいじってほしくないという意思表示
# __ならクラス内からしか読めなくなる(インスタンスからは無理)
self._enable_auto_run = enable_auto_run
# プロパティのゲッター 読み込みしかできなくなる
@property
def enable_auto_run(self):
return self._enable_auto_run
# プロパティのセッター これでセット時に条件を加えられる
@enable_auto_run.setter
def enable_auto_run(self, is_enable):
self._enable_auto_run = is_enable
# オーバーライド
def run(self):
print('auto run')
# インスタンス生成
car = ToyotaCar('model-s')
print(car.model)
car.run()
# プロパティの呼び出し
print(car.enable_auto_run)
# セッターの使用
car.enable_auto_run = True
print(car.enable_auto_run)
# 抽象クラス
import abc
class Human(metaclass=abc.ABCMeta):
# 実装が必要な関数
@abc.abstractmethod
def drive(self):
pass
class Adult(Human):
def drive(self):
print('ok!')
adult = Adult()
# 多重継承
class PersonCarRobot(Person, Car):
def fly(self):
print('fly')
コマンド実行
import subprocess
# コマンド, オプション
subprocess.run(['ls', '-al'])
# shellで直接実行(シェルインジェクション注意!)
subprocess.run('ls -al | grep test', shell=True)
# 戻り値で結果が見れる
r = subprocess.run('aaa', shell=True)
print(r.returncode)
コマンドライン引数
import sys
print(sys.argv) # 引数一覧
import argparse
parser = argparse.ArgumentParser()
# int型のsquareという引数を求める
parser.add_argument("square", type=int,
help="display a square of a given number")
# -vオプションが入ると、verbose変数にTrueが入る
parser.add_argument("-v", "--verbose", action="store_true",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
print("the square of {} equals {}".format(args.square, answer))
else:
print(answer)
python lesson.py option1
# ['aaa.py', 'option1']
# usage: aaa.py [-h] [-v] square
# aaa.py: error: argument square: invalid int value: 'option1'
python lesson.py 2
# ['aaa.py', '2']
# 4
python lesson.py -v 2
# ['aaa.py', '-v', '2']
# the square of 2 equals 4
パッケージと配布
- プログラムを作成
- setup.pyを作成
- python setup.py sdist --formats=gztar,zip を実行
- その階層にdist>name-version.tar.gz (.zip) ができている
- このファイルを展開して、ソースコードを実行できる
mymodule
└─module
__init__.py
Module.py
__init__.py
main.py
setup.py
- setup.py
from setuptools import setup, find_packages
setup(
name='mymodule',
version='1.0.0',
package=find_packages(),
url='example.my-package.com',
license='MIT',
author='kikusan',
author_email='',
description=''
install_requires=['requests'] # 依存関係を指定
)
- module>Module.py
import requests
def say_hello():
r = requests.get('https://www.google.com')
print("hello", r.status_code)
- main.py
from module import Module as m
if __name__ == '__main__':
m.say_hello()
古いVersionだと__init__.pyがないとパッケージとして認識されない。今(3.8)でもあったほうが無難。
__init__.py があるフォルダはパッケージとして認識される。
基本的にパッケージを作るときはルートから枝フォルダまで全てに__init__.pyを用意する。
*でimportするときは __init__.pyに__all__を指定する
__all__ = ['animal']
ファイル操作
# 書き込み バイナリは'rb' 書き込み読み込みしたいとき'w+'
with open('test.txt', 'w') as f:
f.write('line1\n')
f.write('line2\n')
# 読み込み バイナリは'wb'
with open('test.txt', 'r') as f:
print(f.read()) # 全部読む
print(f.tell()) # 今居る位置
f.seek(1) # 位置を移動
while True:
# chunk = 4 # x文字ごとに読み出す場合はf.read(chunk)
line = f.readline()
print(line)
if not line:
break
# csv操作
import csv
with open('test.csv', 'w') as f:
fieldnames=['name', 'count']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'name': 'A', 'count': 1})
with open('test.csv', 'r') as f:
reader = csv.DictReader(f)
for row in reader:
print(row['name'], row['count'])
import os
import glob
import shutil
print(os.path.isfile('test.txt')) # True
print(os.path.isdir('test.txt')) # False
#os.rename('test.txt', 'renamed.txt') # rename
# os.symlink('renamed.txt', 'symlink.txt') # windowsだとショートカットコピー
os.mkdir('test_dir') # dir作成
# os.rmdir('test_dir') # dir削除
glob.glob('test_dir/*') # 一覧
shutil.rmtree('test_dir') # 全削除
print(os.getcwd()) # pwd
import tarfile
# tar圧縮
with tarfile.open('test.tar.gz', 'w:gz') as tr:
tr.add('test_dir')
# tar展開
with tarfile.open('test.tar.gz', 'r:gz') as tr:
tr.extractall(path='test_tar')
import zipfile
# zip圧縮
with zipfile.ZipFile('test.zip', 'w') as z:
for f in glob.glob('test_dir/**', recursive=True):
z.write(f)
# zip展開
with zipfile.ZipFile('test.zip', 'r') as z:
z.extractall('test_zip')
# tempfileを作ってくれる
import tempfile
with tempfile.TemporaryFile(mode='w+') as t:
# .......
設定を読み書き
import configparser
# configparserで設定を読み書き
config = configparser.ConfigParser()
config['web_server'] = {
'host': '127.0.0.1',
'port': 80
}
with open('config.ini', 'w') as config_file:
config.write(config_file)
config = configparser.ConfigParser()
config.read('config.ini')
print(config['web_server'])
print(config['web_server']['host'])
# yamlで設定を読み書き
import yaml
with open('config.yml', 'w') as yaml_file:
yaml.dump({
'web_server': {
'host': '127.0.0.1',
'port': 80
}
}, yaml_file)
with open('config.yml', 'r') as yaml_file:
data = yaml.load(yaml_file)
print(data, type(data))
logging
基本はloggerを使う。別モジュールからの汚染を防ぐため。
import logging
"""
CRITICAL
ERROR
WARNING
INFO
DEBUG
"""
# フォーマット指定
formatter = '%(asctime)s:%(levelname)s:%(message)s'
# ロガーオプション指定
# basicConfigの設定はロガーに継承される。
logging.basicConfig(filename='test.log', level=logging.INFO, format=formatter)
# メッセージ出力(デフォルトは標準出力)
logging.error('error = {}'.format('message'))
# ロガーを各ファイルで作っておけば、
# そのファイル内の処理はどこで呼び出してもそのファイルのロガーで処理される
# ロガーはnameが一緒ならpythonプロセス内で同一インスタンス
logger = logging.getLogger(__name__)
# いろんなハンドラーをロガーに渡すとロガーそれぞれに設定できる
h = logging.FileHandler('handler.log')
logger.addHandler(h)
logger.info('loggerinfo')
logger.error({
'action': 'create',
'status': 'fail'
})
# getLogger(__name__)はすべてのファイルに書く。
プログレスバー
from tqdm import tqdm
import time
# for のイテラブルオブジェクトをtqdmでラップするとプログレスバーを表示できる
sum_ = 0
before = time.time()
for i in tqdm(range(int(1e7))):
sum_ += 1
print(sum_)
after = time.time()
print('it tool {}'.format(after - before))
json
import json
j = {
'employee':
[
{"id": 111,},
{"id": 222,},
]
}
# str変換
j_s = json.dumps(j)
print(type(j_s))
print(j_s)
# dict変換
j_d = json.loads(j_s)
print(type(j_d))
print(j_d)
# ファイル入力
with open('test.json', 'w') as f:
json.dump(j, f)
# ファイル読み込み
with open('test.json', 'r') as f:
print(json.load(f))