家族持ちと自己研鑽についての日記
家族がいるということは家族との時間を過ごす必要がある。 それは当たり前だが、そうなると必然的に自分だけの時間は減る。
家族を持つことで自分の時間が増えるという人はまずいないだろう。
だから、自分の時間を大事にしたい人は、「結婚をしない」か、「結婚するまでに使い果たす」かだと思う。 特に自己研鑽の場合、多くの人の目的は市場価値の向上だろうけど、それが仕事内容と同じベクトルであれば 自己研鑽に割く時間は少なくても良いと思う。仕事は毎日7.5時間以上あるので、 それが1ヶ月だと約150時間、年間約2000時間ほどである。
もしも仕事が自己研鑽へ直結していなかった場合、これはきつい。 一歩踏み出す勇気があるならば即転職したほうが良い、それは家族を持たないうちにしたほうが良い。 転職する勇気が無いとしても、やはり家族を持たないうちにプライベートの時間を割いて自己研鑽すべきだろう。
しかし問題なのは、このことに、家族を持った後で気づく人が多いということだ(しらんけど、自分はそうだから)。 「子供の頃にもっと勉強していたほうがよかったなあ」と思う大人は多い。それと同じだ。
必要と感じたときには、すでに手遅れなパターンが多い。
- 家族を持っている
- 仕事内容が市場価値向上と一致しない
- 筋トレが趣味
- 睡眠は7時間以上取らないと死ぬ
という自分は、自己研鑽する時間が足りない。これは自分が招いた結果だから自分にしか責任が無い。 睡眠以外はすべて自分の選択による結果なのだ。
それにも懲りず、今はフォートナイトにハマってしまった。 これから先、自己研鑽に当てる時間はほとんど無くなる。
そんな暇があったらフォートナイトのスキルを磨いたほうがいいと感じているからだ。
筋トレも週5だったのを週4に変えて、プログラムも見直している。 具体的には今古賀翔さんのプログラムを採用している。
しかし昨日今日の大雨で、筋トレする時間もまた減ってしまっている(理由は割愛)。 コロナにより1ヶ月自粛筋トレを自粛していたのもあって、以前より筋トレに対する熱が冷めたのだ。 これは間違いない。というか、週5も週4も変わらないんじゃないか、という考えになった。 1回のトレーニングを充実させれば、むりそ週4のほうが効果があるのでは?と。 そして週4に減らして1回のトレーニングを妥協し始めている。
すべてが惰性へと傾いているのだ。
仕事なんてしたくない。
自分の時間がほしい。
フォートナイトうまくなりたい。
Netfixでイコライザー2が観たい。
FPS Freek Vortex買った。
機械学習もっと勉強したい。
でもフォートナイトがうまくなりたい。
エイムリング買った。
背面パッドほしい。
最近はもっぱらこんな感じで葛藤しているのである。
【LeetCode】Climbing Stairs 解法【Python】
Climbing Stairs
動的計画法のジャンルとして紹介されていたので解いてみたが、 なんとなく動的計画法ぽいなあと思いつつ具体的な解放が思いつかず。 ツリー構造で表現してみる。
これはn=3のとき。ノードの部分の残りの数が同じ場合は、その子は同じ構造になる。 最終的にエッジの数を数えればいい。 で、n=4のときは?最初の分岐で、1と2に分かれて、1の方は残り3になるので、n=3の構造と一緒。 そして2の方は残り2になるのでn=2と一緒。 これ、フィボナッチで表せそう。ということで解法。
コード
class Solution: def climbStairs(self, n: int) -> int: # 合計nになる1,2の組み合わせ # 0 = 1 # 1 = 1 # 2 = 2 # 3 = 3 # 4 = 5 # 5 = 8 # ※便宜上0 = 1とする ret = [1]*(n+1) for i in range(1,n): ret[i+1] = ret[i] + ret[i-1] return ret[n]
実際にsolutionでフィボナッチの解き方が紹介されており、 自分の解法のような愚直なコードではなく、公式一発だった。
また、動的計画法についてはこちら。
i番目に到達できる経路を順次計算していく、という。自分のコードは結果的に動的計画法のやり方になっていた。
【LeetCode】Reverse a Linked List 解法【Python】
Reverse a Linked List
独自のリンクリストクラスを逆順にする問題。こういうのは現実問題として結構多いと思う。 解放としては、愚直にやるしかないって感じ。再帰使ったやりかたもあるが、可読性が下がるのであまり好きじゃない。
leetcodeの記述を前提としているのでヘルパークラスみたいな実装になっているが、 実際はリンクリストクラス自身にreverseをつけてもいいと思うんだが、どうなんだろ。
コード
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def reverseList(self, head: ListNode) -> ListNode: if head is None: return None next_ = head.next pre_node = ListNode(val= head.val, next=None) if next_ is None: return pre_node while next_ is not None: val = next_.val nxt = pre_node rev_node = ListNode(val=val, next=nxt) pre_node = rev_node next_ = next_.next return rev_node
ちょっとコードが汚い。 headがNoneのときはいいとして、 headだけで終わっている場合(連結がない場合)のifは不要だと思うのできれいにできそう。
solutionに書いてあったきれいなコード↓
class Solution: # @param {ListNode} head # @return {ListNode} def reverseList(self, head): prev = None while head: curr = head head = head.next curr.next = prev prev = curr return prev
【LeetCode】Sum of Two Integers 解法【Python】
Sum of Two Integers
加算と減算を計算する関数を作る、ただし+と-を使わずに。という問題。 これは流石にわからなかった。バイナリ演算というのは想像できるが、 実際のアルゴリズムを考える余力もなく、答えをみた。
コード
class Solution: def getSum(self, a: int, b: int) -> int: MAX_INT = 0x7FFFFFFF MIN_INT = 0x80000000 MASK = 0x100000000 while b: carry = (a & b) a = (a ^ b) % MASK b = (carry << 1) % MASK if(a <= MAX_INT): return a else: return ~((a % MIN_INT) ^ MAX_INT)
しかし、普通に+と-使って計算したときと処理速度変わらないのだが、
これを使う場面があるのだろうか。
【書評】OpenSSH[実践]入門:テレワーク時の仕事ハックのために
勤めている会社ネット環境がクソすぎてテレワークが許可されても全然仕事ができない状態だった。 sshのポートを許可してくれと懇願してそれだけはOKをもらった。 (それにしても、あれだけ敏感になっておいて22番ポートを開けるリテラシーのなさよ。)
んでsshが使える環境になったので、その範疇でやれることをやりたいと思って購入したのがsshの本である。
![OpenSSH[実践]入門 (Software Design plus) OpenSSH[実践]入門 (Software Design plus)](https://m.media-amazon.com/images/I/51Dsiu40MbL._SL160_.jpg)
OpenSSH[実践]入門 (Software Design plus)
- 作者:川本 安武
- 発売日: 2014/11/01
- メディア: 単行本(ソフトカバー)
sshだけでこの分厚さは想像以上ではあったものの、sshに関する本はあまり出版されていなかったので選択肢はほぼなかった。 この本は評価もそこそこ高いし、「実践」「入門」というワードに釣られてしまった。
ネットである程度調べて実践していたが、それでも知らない点がたくさんあった。 そもそも、なんのために使うんだ?というような章もある。これは、結構な人数を管理するための機能なんだろうけど、自分の場合は数人レベルなので、今は関係ないとおもって斜め読みした。 単純に、sshでリモートログインして開発してますよ、という人は一度読んでおいて欲しい。 まじか、こういう使い方があるのか、など新たな発見は間違いなくある。 個人的にはGoogle Authenticatorをサポートしていることにびっくりした。
個人的付箋
ポートフォワードの追加と削除
エスケープキャラクタ(デフォルトはチルダ~)のあとにCを入力するとコマンドラインが開き、プロンプトがsshに変わる。 例えば、ヘルプを表示する。
$ ~C ←実際には~Cは表示されない ssh> help Commands: -L[bind_address:]port:host:hostport request local forward -R ・・・ ・・・
インターネットに接続できない環境のホストをアップデートする
ポートフォワードとtsockを組合せえれば、ネットワークから切り離されたOSをアップデートさせる経路を作れる。まず、リモートポートフォワードを有効にして接続し、隔離されたホストがクライアントのsshdに接続できるようにする。 10022はクライアントのsshdに繋がるポート。
[client]$ ssh -R 10022:localshot:22 remotehost
つぎにダイナミックポートフォワードを有効にし、クライアントをSOCKSのプロキシにする。
[remotehost]$ ssh -D 1080 -p 10022 localhost
tsocksはプロキシエンドで名前解決ができる。remotehostはクライアントをプロキシにしてインターネットを接続することが可能になる。
[remotehost]$ tsocks yum update
Match(条件分岐)
OpenSSH-6.5から、SSHクライアントのコンフィグファイル内でキーワードによる条件分岐ができるようになった。
Matchで使用できるキーワード
- exec
- host
- originalhost
- user
- localhost
execで展開されるトークン
- %L
- ローカルマシンのホスト名の最初のドットまで
- %l
- ローカルマシンのホスト名
- %h
- 接続するリモートマシンのホスト名
- %n
- コマンドラインから入力したホスト名
- %p
- 接続するリモートホストのポート番号
- %r
- リモートホストで認証するユーザ名
- %u
- ローカルマシンでsshを実行したユーザ名
設定例
Host web01 HostName 192.168.100.11 Host proxy-server ProxyCommand none Match exec "nmcli connection status id <ap-name> 2> /dev/null" proxyCommand ssh -W %h:%p proxy-server
%hを使用した設定例
Host web01 web02 mail01 mail02 db01 db02 HostName %h.localhost.localdmain
ローカルポートフォワードを複数設定する
複数行で記述可能
LocalForward localhost:8080 192.198.100.100:80 LocalForward localhost:9090 192.198.100.200:80
ProxyCommand
リモートホストへ接続するために使用するコマンドを指定する。 ProxyCommandで使えるトークンは下記。
- %h
- 接続するホスト名
- %p
- 接続するポート番号 *%r
- リモートのユーザ名
暗号方式による転送速度とCPU負荷の違い
書籍の一部を掲載。
【LeetCode】Longest Substring Without Repeating Characters 解法【Python】
Longest Substring Without Repeating Characters
与えられた文字列内で、文字が重複しない範囲の最大の文字数を返却する。
解法
1文字見ていって、重複した時点の1文字前までの文字数を最大候補として、 重複した文字の最初に出てきた場所から再度カウントし直す。 それを繰り返して最大候補の中から最大文字数を返却する。
毎回、重複した文字の最初に出てきた文字まで戻るのはコストなので、 その場所を覚えておき、現在の場所までの文字列をスライス、みたいなふうにして高速化。
コード
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: if s == "": return 0 if len(set(s)) == len(s): return len(s) max_len = str_len = 1 local_s = [s[0]] s_idx = 0 for i in range(1, len(s)): if s[i] in local_s: str_len = i - s_idx max_len = max(max_len, str_len) find_idx = local_s.index(s[i]) s_idx = find_idx+s_idx+1 local_s = local_s[find_idx+1:] local_s.append(s[i]) else: str_len = len(s) - s_idx max_len = max(max_len, str_len) return max_len
ハッシュ使ったらもっと速そう。
solutionに書いていたシンプルなコード(にちょっとだけ手を加えて高速化したもの)
class Solution: def lengthOfLongestSubstring(self, s): """ :type s: str :rtype: int """ str_list = [] max_length = 0 for x in s: if x in str_list: max_length = max(max_length, len(str_list)) str_list = str_list[str_list.index(x)+1:] str_list.append(x) else: max_length = max(max_length, len(str_list)) return max_length
さらに、solutionに書いていた、めちゃ速い解法。 やはりdict使っている。
class Solution: def lengthOfLongestSubstring(self, s): dicts = {} maxlength = start = 0 for i,value in enumerate(s): if value in dicts: sums = dicts[value] + 1 if sums > start: start = sums num = i - start + 1 if num > maxlength: maxlength = num dicts[value] = i return maxlength
【書評】入門Python3 :とりあえず読んでおくべき
ある程度pythonを触った身からすると、読んでおいて損はない本。

- 作者:Bill Lubanovic
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
これが全く触ったことがな人だともしかしたら読みづらいかもしれない。 そもそもオラ本が全般的に初心者に易しくない気はする(head firstシリーズは易しい?)。
上記に当てはまる場合(自分はそう)は、間違いなく優良な本だった。 というのは、やはり実践主義でコードを書いていると、変な癖がつく気がしていて、 それはpythonのポリシーと合っているかわからないし、そもそも無駄な実装をしている可能性もあり、 標準ライブラリを使えば簡単に解決できるのではないか、という不安を抱いて、 この本を読んだらその不安が的中していたからである。
例えば、setクラスはずっと重複なしリストだと思い込んでいた。 「リストから重複を除外したい」と調べたら大体setを使った解法が出てくるため、 そのために作られたクラスなのだと思い込んでしまっていた。実際は集合クラスなので集合演算ができる。 他にもcsvにあるDictReaderやDictWriterも便利だなと思った(pandas使う場面が多いけど)。
とはいえ、イディオムやデザインパターンなどの内容は書いていないため、 この本を読めばシステム開発ができるとまではいかない。 にしても、どのような道具があるのかを知ることできるし、どの場面で使えばいいのかもわかるため、 今後pythonを触るエンジニアは早めに読むことをおすすめする。
個人的付箋
集合クラス
setは集合クラス。重複なしリストかと思ってたが違った。 なので集合演算ができる。
a = {1, 2} b = {2, 3} a & b a.intersection(b) a + b a.union(b)
elseによるbreakチェック
whileやforは、正常終了したかどうかをチェックするオプションのelseを持っている。 ループがbreak呼び出して途中で終了しておらず、最後まで実行されたときにelse内が実行される。
for c in cs: print('hoge') break else: # breakしていない print('fuga')
例外
exrcept exceptiontype as name
short_list = [1, 2, 3] while True: value = input('Position [ q to quit ] ? ') if value = 'q': break try: position = int(value) print(short_list[position]) except IndexError as err: print('Bad index:', position) except Exception as other: print('Something else broke:' other)
存在しないキーの処理
存在しないキーで辞書にアクセスする際の振る舞いについて、 get()関数を使ってデフォルト値を返すようにすれば例外を避けられる。 setdefault()関数はキーがなければさらに辞書を要素に追加することができる。
periodic_table = {'Hydrogen' : 1, 'Helium' : 2} carbon = periodic_table.setdefault('Carbon', 12) # carbon => 12 # periodic_table => {'Hydrogen' : 1, 'Helium' : 2, 'Carbon', 12} # すでにキーがある場合は更新されない helium = periodic_table.setdefault('Helium', 923) # helium => 2 # periodic_table => {'Hydrogen' : 1, 'Helium' : 2, 'Carbon', 12}
defaultdictは辞書作成時にあらゆる新キーのためにあらかじめデフォルト値を設定する。
from collections import defaultdict periodic_table = defaultdict(int) periodic_table['Hydrogen'] = 1 periodic_table['Lead'] periodic_table # defaultdict(<class 'int'>, {'Lead': 0, 'Hydrogen': 1})
特殊メソッド
比較のための特殊メソッド
メソッド | 意味 |
---|---|
__eq__( self, other ) | self == other |
__ne__( self, other ) | self != other |
__lt__( self, other ) | self < other |
__gt__( self, other ) | self > other |
__le__( self, other ) | self <= other |
__ge__( self, other ) | self >= other |
算術演算のための特殊メソッド
メソッド | 意味 |
---|---|
__add__( self, other ) | self + other |
__sub__( self, other ) | self - other |
__mul__( self, other ) | self * other |
__floordiv__( self, other ) | self // other |
__truediv__( self, other ) | self / other |
__mod__( self, other ) | self % other |
__pow__( self, other ) | self ** other |
その他の特殊メソッド
メソッド | 意味 |
---|---|
__str__( self, other ) | str(self) |
__repr__( self, other ) | repr(self) |
__len__( self, other ) | len(self) |
下記でドキュメント化されている。
https://docs.python.org/3/reference/datamodel.html#special-method-names
Guidoのアドバイス
データ構造を作り込みすぎないようにしよう。オブジェクトよりもタプルの方がいい。ゲッター/セッター関数よりも単純なフィールドを選ぶようにしよう。組み込みデータ型はプログラマーの友達だ。数値、文字列、タプル、リスト、集合、辞書をもっと使おう。そして、コレクションライブラリ、特にデックをチェックしよう。
collections --- コンテナデータ型 — Python 3.8.3 ドキュメント
名前つきタプル
from collections import namedtuple Duck = namedtuple( 'Duck', 'bill tail' ) duck = Duck('wide orange', 'long') # duck => Duck(bill='wide orange', tail='long) # duck.bill => wide orange # duck.tail => 'long'
csv
DictReaderを使って辞書リストにすることができる。 各行のキーが、各列のヘッダーとなる。
import csv with open('villains', 'rt') as fin: cin = csv.DictReader(fin, fieldname=['first', 'last']) villanins = [row for row in cin]
DictWriterを使って辞書リストからヘッダー付きのcsvファイルを作成することができる。
with open('dst_villains', 'wt') as fout: cout = csv.DictWriter(fout, ['first', 'last'] cout.writeheader() cout.writerows(villains)
yaml
PyYAMLは文字列からPythonオブジェクトをロードできるが、これは危険なことだ。 load()ではなくsafe_load()を使うべき。
timedelta
from datetime import date, timedelta now = date.today() one_day = timedelta(day=1) tomorrow = now + one_day yesterday = now - one_day # 17日後 now + 17 * one_day
リスト内表記はappend()を使ったリストへの要素追加より速い
result =[] for value in range(1000): result.append(value) # こちらのほうが2倍以上速い result = [value for value in range(1000)]