【Python】 Python ~ namedtuple / 簡易クラス ~

■ はじめに

https://dk521123.hatenablog.com/entry/2011/03/29/234236

のように .NET の タプルのような機能を Python で探していたら
namedtuple (名前付きタプル)に検索に引っかかったので調べてみた

■ namedtuple

公式サイト
https://docs.python.org/ja/3/library/collections.html#collections.namedtuple
用途

* 簡易的なクラスを作成できる

=> 別になくても作れるけど、どうせなら奇麗に作りたいよねって機能

■ サンプル

例1:座標
例2:ファイル情報

例1:座標

from collections import namedtuple

# ここで namedtuple を定義
Point = namedtuple('Point', ['x', 'y'])
point = Point(11, y=22)

print("({}, {})".format(point.x, point.y))

出力結果

(11, 22)

例2:ファイル情報

from collections import namedtuple

FileInfo = namedtuple('FileInfo', ['date', 'file_name', 'full_path'])

file_list = []
file_list.append(FileInfo('2020/11/12', 'sample1.jpg', r'C:\tmp\sample3\sample1.jpg'))
file_list.append(FileInfo('2021/10/12', 'sample2.jpg', r'C:\tmp\sample3\sample2.jpg'))
file_list.append(FileInfo('1922/11/12', 'sample3.jpg', r'C:\tmp\sample3\sample3.jpg'))
file_list.append(FileInfo('2020/10/12', 'sample2.jpg', r'C:\tmp\sample3\sample2.jpg'))
file_list.append(FileInfo('2002/11/12', 'sample3.jpg', r'C:\tmp\sample3\sample3.jpg'))

# 同じファイル名のファイルがあった場合、最新のものをピックアップする
target_file_list = []
for index, file_info in enumerate(file_list):
  if (index == 0):
    target_file_list.append(file_info)
    continue

  # もう少しうまく書きたいし、書けるはず、、、
  removing_file = None
  is_same_name = False
  for target_file in target_file_list:
    if (target_file.file_name == file_info.file_name):
      is_same_name = True
      if (target_file.date < file_info.date):
        removing_file = target_file
        break

  if (removing_file is not None):
    target_file_list.remove(removing_file)
    target_file_list.append(file_info)
  elif (is_same_name):
    print("Skip")
  else:
    target_file_list.append(file_info)

for target_file_info in target_file_list:
  print("({}, {}, {})".format(
    target_file_info.date, target_file_info.file_name, target_file_info.full_path))

file_name_list = [file_info.file_name for file_info in target_file_list]
for file_name in file_name_list:
  print("File name = {}".format(file_name))

print("Done")

出力結果

Skip
(2020/11/12, sample1.jpg, C:\tmp\sample3\sample1.jpg)
(2021/10/12, sample2.jpg, C:\tmp\sample3\sample2.jpg)
(2002/11/12, sample3.jpg, C:\tmp\sample3\sample3.jpg)
File name = sample1.jpg
File name = sample2.jpg
File name = sample3.jpg
Done

参考文献

https://qiita.com/tag1216/items/19fbc1a4f6a24dd7861b

関連記事

Python ~ 基本編 / クラス・継承 ~
https://dk521123.hatenablog.com/entry/2019/08/29/220537
Python ~ 基本編 / タプル・集合 ~
https://dk521123.hatenablog.com/entry/2019/10/26/000000
Python ~ 基本編 / ラムダ lambda ~
https://dk521123.hatenablog.com/entry/2019/09/23/000000

【Hive】Hive / HiveQL ~ テーブル作成 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2020/02/25/231235
https://dk521123.hatenablog.com/entry/2020/06/02/183823

の続き。

長くなったので、テーブル作成だけで分冊。

目次

【1】テーブル作成
 1)CREATE TABLE:内部テーブル作成
 2)CREATE EXTERNAL TABLE:外部テーブル作成
【2】Partition 機能
【3】テーブル・オプション
 1)行の区切りフォーマット
 2)ファイルフォーマットを指定
 3)ヘッダー行を飛ばす
【4】その他
 1)SHOW CREATE TABLE [テーブル名]

【1】テーブル作成

* テーブルは、以下の2種類ある
~~~~~
1)内部テーブル
2)外部テーブル
~~~~~

1)CREATE TABLE:内部テーブル作成

内部テーブルを作成する
 ⇒ 実体は、HDFS(Hadoop Distributed File System)上のファイル
 ⇒ /user/hive/warehouseの下に、データ置き場用のディレクトリが作られる

構文

-- テーブル作成
CREATE TABLE <テーブル名> (
  <項目名> <データ型>,
  …
)
[オプション項目] ...;
-- [LOCATION 'hdfs_path'] (e.g. LOCATION '/user/hive/warehouse')

-- あったら、作成
CREATE TABLE IF NOT EXISTS  <テーブル名> (
...

データ型

以下の公式サイトを参照。

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types

使用上の注意

* DROP TABLE を実行すると、データ置場のディレクトリも削除される

サンプル

-- 例1:HDFS 内にテーブルを作成
CREATE TABLE sample_table (
  id STRING,
  name STRING
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '/user/hive/warehouse'
;

-- 例2:SELECT文 から作成することも可能。
CREATE TABLE hello_world_clone
AS
SELECT
  *
FROM
  hello_world
;

2)CREATE EXTERNAL TABLE:外部テーブル作成

* 外部テーブル(※)を作成する
 => ディレクトリパス(データ置場)を指定してテーブルを作成する
 => データ自体は、外部ファイル

※ 外部ファイル について
ローカルファイルシステム又はAmazon S3上に置かれているデータファイルを
まるで内部テーブルのように扱える仕組み

https://qiita.com/holy_road_ss/items/d55f2d539bf146c2e38d
https://www.atmarkit.co.jp/ait/articles/1701/01/news022_3.html
構文

-- データ置場を指定してテーブルを作成する
CREATE EXTERNAL TABLE <テーブル名> (
  項目名 型,
  …
)
-- パスであってファイル名含むフルパスではない
LOCATION 'ディレクトリパス';

-- あったら作る
CREATE EXTERNAL TABLE IF NOT EXISTS <テーブル名>(
  …

サンプル

CREATE EXTERNAL TABLE hello (
  name STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LOCATION "s3://your-s3-buket/hello";

-- AWS 上での例
CREATE EXTERNAL TABLE person (
  id BIGINT,
  name STRING
)
PARTITIONED BY (created_date INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
LOCATION 's3://your-s3-buket/demo/';
-- s3://your-s3-buket/demo/created_date=20200602/xxxx.csv

使用上の注意

* LOCATION は、パスであって、ファイル名含むフルパスではない
* DROP TABLE を実行しても、データ置場のディレクトリも削除されない

【2】Partition 機能

以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2020/07/16/224332

【3】テーブル・オプション

1)行の区切りフォーマット

サンプル

CREATE TABLE xxx (
  id BIGINT
)
ROW FORMAT DELIMITED
  -- 項目の区切り文字が「,」
  FIELDS TERMINATED BY ","
  -- 行の区切り文字が「\n」
  LINES TERMINATED BY '\n';

2)ファイルフォーマットを指定

サンプル

CREATE TABLE xxx (
  id BIGINT
)
-- PARQUET形式として指定
-- (列志向・カラムナフォーマット: Parquet, ORC / TEXTFILE etc)
STORED AS PARQUET
-- 圧縮形式:snappy
TBLPROPERTIES("parquet.compression"="SNAPPY")
;

https://qiita.com/yskazuma/items/db543d45d32013cfcbb9

3)ヘッダー行を飛ばす

CREATE TABLE xxx (
  id BIGINT
)
-- TBLPROPERTIES = table properties
TBLPROPERTIES ('skip.header.line.count'='1');

https://qiita.com/Takemura-T/items/5f683753063d7bc52cc9

【4】その他

1)SHOW CREATE TABLE [テーブル名]

* 既存のテーブル定義を出力してくれる

サンプル

hive> SHOW CREATE TABLE sample_table;

OK
CREATE TABLE sample_table
  id string,
 ....

関連記事

Hive / HiveQL ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2019/11/25/235219
Hive / HiveQL ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/02/25/231235
Hive / HiveQL ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2020/06/02/183823
Hive / HiveQL ~ データベース関連 ~
https://dk521123.hatenablog.com/entry/2022/05/12/150249
Hive / HiveQL ~ パーティション / 基本編 ~
https://dk521123.hatenablog.com/entry/2020/07/16/224332
Hive / HiveQL ~ データ圧縮あれこれ ~
https://dk521123.hatenablog.com/entry/2021/08/06/172502
Hive / HiveQL ~ HiveQL関数編 ~
https://dk521123.hatenablog.com/entry/2020/03/10/224640
Hive / HiveQL ~ 設定プロパティ ~
https://dk521123.hatenablog.com/entry/2020/09/19/152136
Hive / HiveQL ~ あれこれ編 ~
https://dk521123.hatenablog.com/entry/2020/03/04/225943
hive で固定値を挿入するには
https://dk521123.hatenablog.com/entry/2020/09/22/000000
Hive に関するトラブルシューティング
https://dk521123.hatenablog.com/entry/2020/11/20/174039
Hive / Partition に関するトラブルシューティング
https://dk521123.hatenablog.com/entry/2020/05/28/175428
Hadoop ~ 環境設定 / Linux編 ~
https://dk521123.hatenablog.com/entry/2020/01/01/000000
Hadoop ~ 基本編 / HDFS
https://dk521123.hatenablog.com/entry/2022/05/01/000000

【Python】 Python ~ 基本編 / 関数・あれこれ ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/09/22/000000

の続き。

関数の記事が長くなったので、整理して分冊。

また、Pythonの資格の問題ででてきた
デフォルト引数の注意点などを記録。

目次

【0】関数の実体について 
【1】デフォルト引数
 1)デフォルト引数の使用上の注意
【2】 可変長引数
 1)*args (タプル) ... 可変長引数
 2)**kwargs (辞書) ... 名前付き可変長引数
 3)補足:引数のアンパック(展開)
【3】 キーワード引数
 1)キーワード引数
 2)キーワード引数を強制する*
【4】関数の空実装
【5】内部関数(Inner Function)

【0】関数の実体について

* 関数の正体は、オブジェクトである
* 関数を変数に格納して呼び出すことが可能

サンプル

def sample_method(name):
  print("Hello " + name)

func = sample_method
func("Mike") # Hello Mike

【1】デフォルト引数

 * 「引数 = 初期値」にする

サンプル

def sayHello(name="Mike"):
    print("Hello, {}!".format(name))

sayHello()

 出力結果

Hello, Mike!

1)デフォルト引数の使用上の注意

* リストや辞書などのオブジェクトをデフォルト指定した場合、
 そのオブジェクトは関数定義時に生成され、
 2回目以降に呼び出されたら、同じオブジェクトが使われる。

サンプル

def culc(a, b=1, list1=[], list2=[]):
  print(list1)
  print(list2)
  list1.append(a ** 2)
  list2.append(b ** 3)
  return list1, list2

print("Start")
print(culc(1))
print("*******")
print(culc(2, 3))
print("*******")
print(culc(3, 4))
print("*******")
print(culc(4, 5))
print("Done")

出力結果

Start
[]
[]
([1], [1])
*******
[1] << デフォルト値に前回の値が含まれている
[1] << デフォルト値に前回の値が含まれている
([1, 4], [1, 27])
*******
[1, 4] << デフォルト値に前回の値が含まれている
[1, 27] << デフォルト値に前回の値が含まれている
([1, 4, 9], [1, 27, 64])
*******
[1, 4, 9] << デフォルト値に前回の値が含まれている
[1, 27, 64] << デフォルト値に前回の値が含まれている
([1, 4, 9, 16], [1, 27, 64, 125])
Done

 【2】可変長引数

可変長引数には、以下の2種類ある。

1)*args ... 複数の引数をタプルとして受け取る(可変長引数)
2)**kwargs ... 複数の引数を辞書として受け取る(名前付き可変長引数)

1)*args (タプル) ... 可変長引数

 * 「*【引数名】」にする

サンプル

# coding: UTF-8

def say_hello(*names):
    for name in names:
         print("Hello, {}!".format(name))

say_hello("Mike", "Tom", "Sam")

出力結果

Hello, Mike!
Hello, Tom!
Hello, Sam!

2)**kwargs (辞書) ... 名前付き可変長引数

 * 「**【引数名】」にする

サンプル

def function(**key_values):
    for key, value in key_values.items():
         print("Key = {}, Value = {}.".format(key, value))

def main():
    function(A1='Mike', A2='Tom')

if __name__ == '__main__':
    main()

出力結果

Key = A1, Value = Mike.
Key = A2, Value = Tom.

3)補足:引数のアンパック(展開)

* アンパック (unpack)
  ... リストなどの要素を1つ1つ取り出し(展開)、関数に渡す操作

サンプル

list = ["A", "B", "C"]

print(list) # ['A', 'B', 'C']

print(list[0], list[1], list[2]) # A B C
print(*list) # A B C
print(*list, sep=" => ") # A => B => C

参考文献
https://python.keicode.com/lang/list-unpack-asterisk.php

 【3】キーワード引数

1)キーワード引数

* 引数を明示的に指定可能

 サンプル

def say_hello(greeting="Hello", name="Smith"):
    print("{}, {}!".format(greeting, name))     

say_hello()
say_hello(name="Mike")
say_hello(greeting="Good morning", name="Tom")
say_hello(name="Sam", greeting="Good afternoon")

 出力結果

Hello, Smith!
Hello, Mike!
Good morning, Tom!
Good afternoon, Sam!

2)キーワード引数を強制する*

* 以下「(value1, value2, *, arg1=1.0, arg2=0.0):」のように
 アスタリスクを指定すると、アスタリスク以降の引数を指定する場合
 メソッドの使用者側にキーワード引数を強制的に指定させる

https://yohhoy.hatenadiary.jp/entry/20150315/p1

 サンプル (NGケース)

def sample_method(value1, value2, *, arg1=1.0, arg2=0.0):
  print("{} {} {} {}".format(value1, value2, arg1, arg2))

sample_method(1, 2) # ここはOK
sample_method(1, 2, 1) # NG

 出力結果

1 2 1.0 0.0
Traceback (most recent call last):
  File "c:/work/hello/hello.py", line 5, in <module>
    sample_method(1, 2, 1)
TypeError: sample_method() takes 2 positional arguments but 3 were given

 サンプル (OKケース)

def sample_method(value1, value2, *, arg1=1.0, arg2=0.0):
  print("{} {} {} {}".format(value1, value2, arg1, arg2))

sample_method(1, 2) # ここはOK
sample_method(1, 2, arg1=1000) # OK

 出力結果

1 2 1.0 0.0
1 2 1000 0.0

【4】関数の空実装

 * pass を使う

サンプル

# coding: UTF-8

def sayHello2():
    pass

sayHello2()

出力結果

* 実行しても何も起こらない 

【5】内部関数(Inner Function)

* 関数内で関数を定義できる
* nonlocal については、以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2019/12/12/232749

* 以下のハノイの塔に関する動画でも用いられている

https://www.youtube.com/watch?v=MLronWYaHw8

サンプル

def outer():
  print("外部関数")

  def inner():
    print("内部関数")

  # 外部関数から内部関数を呼び出す
  inner()

outer()

出力結果

外部関数
内部関数

関連記事

Python ~ 基本編 / 関数 ~
https://dk521123.hatenablog.com/entry/2019/09/22/000000
Python ~ 基本編 / 文字列 ~
https://dk521123.hatenablog.com/entry/2019/10/12/075251
Python ~ 基本編 / global・nonlocal ~
https://dk521123.hatenablog.com/entry/2019/12/12/232749
Python ~ 基本編 / yield ~
https://dk521123.hatenablog.com/entry/2021/03/18/000000