【Windows】PDFファイルのサイレント印刷(自動印刷)のやり方

はじめに

こんにちは、SHOJIです。

WindowsでのPDFファイルの自動印刷に苦戦したので、同様の悩みを持つ方に向けて対処方法を残します。

Adobe Acrobat Reader DC での自動印刷

Acrobat Reader での自動印刷の方法は、調べればすぐに情報が出てきますので割愛します。 この方法の問題は、自動印刷した後にプロセスが残ってしまう点です。

プロセスが残っても悪さをしないなら見逃す手もあるかと思います(個人的には悪さをしなくても許容し難いですが……)。


ただ、たとえばプロキシ環境では認証情報を入力するダイアログが立ち上がりまして、このダイアログを閉じないと次の自動印刷が行われないという問題が起きます。

このダイアログは一度閉じれば消えるのですが、端末を再起動した後に毎回ダイアログを閉じる手順を踏まないといけないですし、一週間、一ヶ月経っても再度ダイアログが開かれないかは未検証です。そもそも、少し動かしただけで気づける問題がこれというだけで、他にも問題があるかも知れません。

そう考えると残存プロセスを残すのは避けるべきです。そしておそらく、この記事にたどり着く方も Acrobat Reader のプロセスを残さないよう試行錯誤した末にここまで来たのだと思います。

Adobe Acrobat Reader DC のプロセスを残さない方法

結論から言うと諦めました。 検索すると Acrobat SDK を使った方法等、いくつか見つかると思います。

じゃあ、その方法を採用しようと SDK をダウンロードしに行ってもリンクが切れていたり(https://helpx.adobe.com/jp/acrobat/kb/2558.html)、満足な説明が得られなかったりで、無理して Adobe でやる必要ないという結論に至りました。

Foxit Reader を採用しました

Acrobat Reader の代わりに、 Foxit Reader を採用しました(https://www.foxit.co.jp/products/foxit-reader/)。

詳細な使い方はこちらのマニュアルを参照してください(https://www.foxit.co.jp/wp-content/uploads/FoxitReader82_UserManual.pdf)。

サイレント印刷するだけならば、Foxit Reader をインストールして、

コマンドラインFoxitReader.exe /t [PDFファイルのパス] [プリンタ名] するだけで出来ます。


以上です。

【Firebase】firebase projects:list で「HTTP Error: 401, Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.」が発生する

はじめに

こんにちは、SHOJIです。

Firebaseで発生したエラー対応の備忘録です。

firebase projects:list 実行でエラーが発生

久しぶりにFirebaseのソースを直そうと思い、作業ディレクトリで firebase projects:list コマンドを叩いてみたら「Update available 8.2.0 → 8.5.0 ││ Run npm i -g firebase-tools to update」とのメッセージが表示されました。


指示通り npm i -g firebase-tools to update を実行してツールを更新し、再度コマンドを実行するも今度は「Error: Failed to list Firebase projects. See firebase-debug.log for more info.」とのエラーが発生。


これまた指示に従ってデバッグログを確認すると、次のようなエラーメッセージが……。

[debug] [2021-01-11T14:57:02.753Z] HTTP Error: 401, Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [debug] [2021-01-11T14:57:02.956Z] FirebaseError: HTTP Error: 401, Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. at module.exports (/opt/node-v12.16.3-linux-x64/lib/node_modules/firebase-tools/lib/responseToError.js:38:12) at Request._callback (/opt/node-v12.16.3-linux-x64/lib/node_modules/firebase-tools/lib/api.js:41:35) at Request.self.callback (/opt/node-v12.16.3-linux-x64/lib/node_modules/firebase-tools/node_modules/request/request.js:185:22) at Request.emit (events.js:310:20) at Request.EventEmitter.emit (domain.js:482:12) at Request.<anonymous> (/opt/node-v12.16.3-linux-x64/lib/node_modules/firebase-tools/node_modules/request/request.js:1154:10) at Request.emit (events.js:310:20) at Request.EventEmitter.emit (domain.js:482:12) at IncomingMessage.<anonymous> (/opt/node-v12.16.3-linux-x64/lib/node_modules/firebase-tools/node_modules/request/request.js:1076:12) at Object.onceWrapper (events.js:416:28) at IncomingMessage.emit (events.js:322:22) at IncomingMessage.EventEmitter.emit (domain.js:482:12) at endReadableNT (_stream_readable.js:1187:12) at processTicksAndRejections (internal/process/task_queues.js:84:21)


とりあえず、指示に従おうと「See https://developers.google.com/identity/sign-in/web/devconsole-project.」に記載のURLへアクセスして試行錯誤するも上手く行かず。

そもそもログインしてないのでは?と firebase login してみるものの、「Already logged」と言われる状態。


打つ手がないので一旦 firebase CLI を消そうと考え、一応その前にログインし直してみようと、firebase logout して firebase login したところ事象が解消されました。


釈然としなくて firebase の token 絡みのトラブルについてググったら、一時間程度でトークンの有効期限が切れるという記事を見つけました。が、これまでは何時間、あるいは何日経っても問題なかったのに、どうして今回はエラーになったのかは分からずじまいでした(Firebase側で何か変更があったとか?)。


この件はあまりしっかり調べる気になれなかったので、中途半端ですが対処法だけ残して終えたいと思います。

以上です。

【React】ReactでHTMLカスタムタグを作る

はじめに

こんにちは、SHOJIです。

ReactでHTMLカスタムタグを実装しようと調べていたら、素晴らしいコードを提供している方がいらっしゃったので紹介させて頂きます。

React Custom Tags

https://codepen.io/BradDenver/pen/ALrXaW?css-preprocessor=less

こちら、Reactを使ってVue.js等で見られるHTMLのカスタムタグを実装したサンプルコードです。

リンク先が全てなのでこれ以上の説明は蛇足なのですが、自分の勉強も兼ねてリンク先のコードが何をしているのか説明していきたいと思います。

render関数が行っていること

カスタムタグを実現する上で一番基本となっているのがrender関数です。

// custom tags
function render (tag, Comp) {
  document.createElement(tag);

  const nodes = Array.from(document.getElementsByTagName(tag));
  nodes.map((node, i) => renderNode(tag, Comp, node, i));

  return Comp;
}

コメントに custom tags とあるように、ここでカスタムタグを登録しています。

登録というと少し語弊がありますね。実態に即した表現をすると、「カスタムタグとみなしたタグの下に、React要素を配置している」になります。

ここちょっと細かい話になるのですが、この表現の違いから意識してほしいのは処理の順番が違うということです。

事前にカスタムタグをどこかに登録しておくと、そのどこかがHTML内のカスタムタグを自動的に処理してくれるというわけではありません。render関数が呼び出されるたび、引数で指定されたタグをHTMLから見つけ出して、その場で一つ一つにReact要素を配置しています。


  const nodes = Array.from(document.getElementsByTagName(tag));
  nodes.map((node, i) => renderNode(tag, Comp, node, i));

このように、上の行で引数のtagと合致するタグをHTMLから全て取得して、下の行で取得したタグを引数に renderNode関数を呼び出しています。

renderNode関数が行っていること

続きまして、render関数から呼び出されるrenderNode関数について。

function renderNode (tag, Comp, node, i) {
  let attrs = Array.prototype.slice.call(node.attributes);
  let props = {
    key: `${ tag }-${ i }`,
  };

  attrs.map((attr) => props[attr.name] = attr.value);

  if (!!props.class) {
    props.className = props.class;
    delete props.class;
  }

  ReactDOM.render(
    <Comp { ...props }/>,
    node
  );
}

これはReact要素の配置を実際に行っている関数です。


  let attrs = Array.prototype.slice.call(node.attributes);

ここで node(置き換え対象のタグ)に設定されている全ての属性を取得しています。 属性というのは、サンプルHTMLの name="Jack" です。今回は一つですが、複数設定されていれば複数取得します。


  attrs.map((attr) => props[attr.name] = attr.value);

取得した属性を propskey-value の形で格納し、

  ReactDOM.render(
    <Comp { ...props }/>,
    node
  );
}

最後に props をReact要素の Comp に引き渡しています。 この Comp は元を辿っていくとReactクラスの Hello が設定されているので、ここで node (置き換え対象のタグ)に属性を引き継いだ Hello を設定していると分かります1


おや?と思うとしたらこちらでしょうか。

  if (!!props.class) {
    props.className = props.class;
    delete props.class;
  }

ここではタグの属性である classclassName に置き換えてます。 Reactでは classclassName と書く決まりがあるのでそれに合わせた形ですね。props に一番最初に設定した key もReactのルールに合わせたものです。

まとめ

  • render関数:引数で指定されたタグをHTMLから見つけ出して、renderNode関数を呼び出す。

  • renderNode関数:引数で指定されたDOMノードの属性を引き継いだ上でReact要素をレンダーする。

  • これらによって呼び出し元は render(カスタムタグ名, React要素) とするだけでよい。


今回ご紹介した方法は、結果を見たあとでは公式のレンダー方法を踏襲した非常に素直な方法に見えると思います。ただ、これが自分ではなかなか発想できないんですよね。

少なくとも僕は思いつかなくて、ソースを見た時に「その手があったか!」と思いつけなかったことに悔しさを感じました。

いずれはこういう方法を思いついて発信できる側になりたいですね。



  1. React要素をDOMノードにレンダーする方法はこちらをご参照ください。https://ja.reactjs.org/docs/rendering-elements.html#rendering-an-element-into-the-dom

【読書感想文】『アポロ13』に学ぶITサービスマネジメント〜映画を観るだけでITILの実践方法がわかる!〜が面白い

はじめに

こんにちは、SHOJIです。

「『アポロ13』に学ぶITサービスマネジメント〜映画を観るだけでITILの実践方法がわかる!」が面白かったので、今回はこちらの書籍の紹介をしたいと思います。

www.amazon.co.jp

アポロ13』に学ぶITサービスマネジメントってどんな本?

ITサービスマネジメント(ITSM)の考え方を、映画「アポロ13」に照らして教えてくれる本です。基本的には映画を見た上で読む本ですが、映画を見てなくても理解できるような構成になっています。

なっていますが、面白い映画ですし2時間ちょっとで見られますから、映画→本の順序で見ることをオススメします。せっかくこういう本で勉強するなら、しっかり楽しんで勉強した方がいいと思うんですよね。映画の2時間すら惜しむくらいなら最初からITILのテキストを読んだ方が手っ取り早いわけですし。


そもそも、ITSMやITILって何なの?という方に向けて説明すると、ITSMはITサービスを安定的・継続的に提供するための管理手法のことで、ITILはITSMのベストプラクティスをまとめたものです。実際の開発の現場で言うところの運用や保守を上手く回すための考え方と思ってもらえればイメージしやすいでしょうか。

実際には設計・開発の段階からITSMを考慮してシステムを構築するので全工程に関係のあるものなのですが、最初のつかみとしては「運用・保守のための考え方」くらいに捉えてよいと思います。

目次と感想

■第1部 ITサービスマネジメントアポロ13

●第1章 ITサービスマネジメントとは -ITサービスの価値を高めるために-

●第2章 『アポロ13』でITSMを学ぶ意義 -アポロ計画とビジネスストラテジの共通点-

■第2部 サービスストラテジ

●第3章 「ニール・アームストロングが月に降り立ちました」 -アポロ計画における戦略-

●第4章 「14号があればだが」 -アポロ計画における「顧客」とは-

●第5章 「月を歩くんだね」 -サービスという単位を考える-

■第3部 サービスオペレーション

●第6章 「ヒューストン、 センターエンジンが停止した」 -インシデント管理-

●第7章 「反応バルブを閉じろ、と伝えろ」 -サービスデスク-

●第8章 「自分の字が読めないんだ。思ったより疲れているみたいだな」 -問題管理-

■第4部 サービスデザイン

●第9章 「絶対に死なせません」 -サービスレベル管理-

●第10章 「チャーリー・デュークが風疹にかかっている」 -可用性管理-

●第11章 「問題は電力だ。電力がすべて」 -キャパシティ管理-

●第12章 「トラブルが発生した」 -ITサービス継続性管理-

■第5部 サービストランジション

●第13章 「なんとかして、この四角をこの筒にはめ込むんだ」 -構成管理-

●第14章 「この飛行計画は忘れよう」 -変更管理-

●第15章 「こちらヒューストン。打ち上げ準備完了です」 -リリース管理-

■第6部 継続的サービス改善

●第16章 アポロ計画は改善のかたまり -継続的サービス改善-


ITSMの教科書としてもよくできていますが、それ以前に単純に読み物として面白かったです。 目次からして、映画の印象的なセリフにITILのプロセスを関連付けて興味を惹くようになっています。 僕はこの目次に目を通した時に「この本は当たりだな」と思いましたし、実際それは正しかったです。


第一章の導入で、ITサービスとは何か? なぜITサービスマネジメントが必要か? ITILがどう役に立つか? の説明があり、その後の章でITILをベースにITSMの考え方を解説していく形です。ITILはなかなかにボリュームがあって全ては網羅できないので、大切な部分をピックアップして解説されています。したがって、ITILの資格試験のために読むには適さない本です。これからITILを勉強する方が取っ掛かりにするか、逆にITSMやITILを知っている方がおさらいしたり理解を深めるのに適した本と言えます。


ちなみに、僕はどちらかというと前者で、実務で運用・保守を行った経験はあるものの、ITSMを体系的に学んではいない状態で読みました。そのため、実務で何の気なしにやっていたことがITILでしっかりと定義されていることに気づきまして、それがITILをきちんと勉強するキッカケになりました。

たとえば、第3章の問題管理とインシデント管理の違いについて、実務でも当然ここで定義されているような行動を取っていたのですが、具体的にプロセス名や定義を知ったのはこの本を読んででした。定義を知ることって大事で、漠然としていた物事の解像度が上がるというか、知識として捉えることができるようになるんですよね。人と話す時にも共通言語があると便利ですし、基本的な用語と定義は抑えておくべきだなと思いました。


他に読んでいて特に面白いと思ったところとして、第5章のサービスの3つの分類は良かったです。サービスを「コア・サービス」「実現サービス」「強化サービス」に分類するという考え方で、これまでこのような分類でサービスを考えたことはなかったので新鮮でした。

第6章〜第8章にかけてのインシデント管理や問題管理についての話は、ITに関わる人なら外さない内容だと思います。特に第8章の「火事が少ない地域の消防団の話」は、非常によくある話なので頷きながら(あるいは涙しながら)読めるはずです。

第9章のSLAの章では、多くの会社はSLAと言いつつただの契約書を作っているとの指摘があるのですが、これもIT企業あるあるとしてニヤリとできる話でした。

長くなるのでこのあたりで打ち止めにしますが、どの章もIT企業勤めなら身近に感じられて、かつ大切なテーマになっています。

最後に

もしかしたら、これは弊社だけの話で一般化できないかも知れませんが、管理職は開発が円滑に進まないことよりも、リリースしたサービスにトラブルが発生することを心配する傾向にあると感じます。

開発の方はテコ入れしてこっそりリカバリできる余地がありますが、運用中のトラブルはクレーム入って即問題化しますからね。なので、ITSMの知識があって心配の種である運用を円滑に薦められる人間は上司からの評価を得やすいです。それが理由というわけではないのですが、抑えていて損はない内容ですのでぜひ読んでみてください。

【読書感想文】CAREER SKILLS ソフトウェア開発者の完全キャリアガイドを読んで

はじめに

こんにちは、SHOJIです。

今回はタイトルの通り、「CAREER SKILLS ソフトウェア開発者の完全キャリアガイド」を読んだ感想を書いていきます。本当は7月に書く予定だったのですが、なかなかに分厚い本で読了に時間がかかり、気づけば9月になっていました。さすがに間隔開けすぎたなと反省しています。

CAREER SKILLSってどんな本?

ソフトウェアエンジニアがキャリアを築き、そして成功するため、必要なスキルや知識についてまとめた本です。

www.amazon.co.jp

扱う範囲はかなり広範で、ソフトウェアエンジニアの種類、必要な知識、就職の仕方に始まり、同僚や上司との付き合い方、昇給の仕方、会社員以外の働き方等、どういう専門かに関わらずエンジニアであれば誰もが心得ておくべき内容が網羅されています。一ページの文量はそれほど多くないとはいえ、650ページありますので扱う範囲も相応に膨大です。

なぜ読もうと思ったか

自分の今後のキャリアを考える手助けになると思ったからです。

僕は今31歳、新卒で入社した会社に9年務めています。僕が自分の市場価値を気にしだしたのは2年目の秋からです。

当時はプログラミングの素人だったため仕事で結果が出せず、とても辛い状態でした。そして、このまま今の会社を続けるのは難しいと考えて転職サイトに登録したのですが、そこでスキルシートが全く書けないことに気づきました。

書いたことのある方なら分かって頂けると思いますが、スキルシートで大切なのは「何ができるのか」なので、自分のスキルを意識せずに漠然と仕事をしてても大した内容は書けないんですよね。経歴だけを書いた薄い内容になってしまいます。

その時、仕事をこなすこととスキルを身につけることは似て非なるものだと知り、仕事とは別に自分のプロダクトを作るようになりました。そこから今に至るまで5年以上、マイペースにですが自分のプロダクトを増やすことを続けてきました。


今のプロダクトの内訳としては以下の状態です。このうちストアなどで公開しているのは5本です。

  • Androidアプリ:3本

  • Unityアプリ:1本

  • Windowsアプリ:1本

  • Webアプリ:1本

  • Chrome Extension:1本

ネットを見ていると頑張ってる方が大勢いるので、この程度ではまだまだ全然って感じですが、世間一般から見るとそれなりにやっている方かと思います(自分に甘いですかね?)。

大変有り難いことに公開しているプロダクトやGithubを見た方からスカウト頂くこともあります。

ただ、そろそろ頭打ちと言いますか、同じことを続けるだけでは30代が終わる頃に望むキャリアは築けないと感じています。

これからどうなりたいのか

これが決まらないとキャリアを築くと言っても何をすればいいのか分かりません。

そこで僕が最低でも決めなければいけないと考えたのは次の3つです。

  1. このままソフトウェアエンジニアとして専門性を磨いていくか、プロジェクトマネージャーに転向するか
  2. 組織で偉くなることを目指すか、現状維持でいいか、あるいは個人事業主のような立場を目指すか
  3. 今の会社で頑張るか、会社を移るか


すぐに答えを出せそうですが、そう簡単ではありませんでした。というのも、これらの問いはバラバラに考えれるものではないんですよね。

僕の場合、1は「ソフトウェアエンジニアとして専門性を磨きたい」で決まっています。そうすると、2の「組織で偉くなることを目指す」のは難しくなりそうです。自社の管理職はプロジェクトマネージャーとしての役割を求められることが多いためです(全員とは言いませんが……)。

この時点で会社に残るなら現状維持でソフトウェアエンジニアとしての専門性を磨くことが有力になりますが、現状維持ではよほど上手く立ち回らないと40歳50歳と年を重ねるごとに立場が悪くなりそうな気もします。

じゃあ転職や独立が良いのか? もちろん選択肢としてはアリです。ただ、家族もいますし安易には決められない話です。会社を辞めるのなら、せめて10年先くらいまでの絵は描いておきたいと思いました。

こういったことを今年の6月〜7月にかけて毎晩悩んでいまして、そんな時に見つけたのが「CAREER SKILLS」でした。

読んだ感想

最初に目次を記載して概要を説明してから感想に入ろうと思ったのですが、60章のタイトルを書くだけでもけっこうな量になるのでやめます。目次が気になる方はこちらで確認してみてください。

honto.jp

ここまで何度かボリュームがあることをお伝えしましたが、読む労力を加味しても読んでよかったと思います。 筆者が会社員→フリーランス→起業家という流れを汲んでいるため、それぞれの働き方の長短をしっかり捉えている印象です。特に今回は私の読みたい内容が「会社員以外の働き方を含めたキャリアの構築方法」だったので、まさに知りたい内容にマッチした本でした。

たとえば「第48章 社会的な評価を築く」の章では、会社員として給料が頭打ちになったと感じていた筆者が、ブログで有名になったことで大きなチャンスを獲得した話が書かれています。 これだけでは再現性の低いただのサクセスストーリーですが、この経験を基に「有名になることの利点」や「個人ブランドの作り方」について解説している部分は、会社員かフリーランスかに関わらず、キャリアの築き方として参考にできる内容です。

「個人ブランドの作り方」というとちょっと胡散臭いですが、SNS炎上マーケティングをして注目を浴びよう!みたいな話ではなく、エンジニアとして地道に評価を上げるため何をすべきかという話になっています。

個人的に気に入ったのは、他人のために価値を生み出すことが結果的に自分の評価を高めることになる、という考え方ですね。急がばまわれ、ではないですが、誰かに価値を提供することが巡り巡って本人の価値を高めることに繋がるというのは会社でも見かける光景です。この自分から先に与えるという考え方は筆者の根底にあるもののようで、ここ以外にも度々出てきています。


僕がこの章を読んで思ったことは、キャリアを築くことは会社員やフリーランスといった働き方にさほど影響されないんじゃないかということです。

当初は以下のように、どのような働き方や立場を目指すかを決めて、それに向けてキャリアを築こうと考えていました。

これが決まらないとキャリアを築くと言っても何をすればいいのか分かりません。

そこで僕が最低でも決めなければいけないと考えたのは次の3つです。

  1. このままソフトウェアエンジニアとして専門性を磨いていくか、プロジェクトマネージャーに転向するか
  2. 組織で偉くなることを目指すか、現状維持でいいか、あるいは個人事業主のような立場を目指すか
  3. 今の会社で頑張るか、会社を移るか

このように目標に照準を合わせて取り組む方法が悪いとは言いませんが、今は必ずしも明確なビジョンを固めずともよいかなと考えています。それはどのような働き方をするかに関わらず、やるべきことの根底は「自分の価値を高めること」で共通するからです。

キャリアを築くことは「自分の価値を高める」程度に設定しておいて、どこを自分の価値としてどう伸ばすかに力を入れた方が将来的な選択肢は広がるように思います。もちろん、最初から明確な目標がある場合はそこに向けて最短ルートを走るのが賢いと思いますが。

自分の価値を高めるという話に対しては、「スキルを高めたところで評価に反映されるとは限らない」とツッコミが入りそうですが、これは「自分の価値≠スキル」であって「自分の価値=スキル+評価」なのだと思います。自分の価値にはスキルだけでなく評価も含まれると考えて、どのように評価を得るかまで考える必要があるのでしょう。そういった評価の上げ方についてもこの本の中で触れられています(ただ、この部分に関しては目新しい話はありませんでした)。

本を読む前、今のままでは望むキャリアを得られないと感じていた原因は、この評価の部分を考えていなかったからです。プロダクトを作ってスキルを伸ばせばいい期間はもう終わっていて、作ったものや身につけた知識を発展させていく方法を考えることが自分の課題になりそうです。このあたりの考えを整理できただけでも読む価値はあったと思います。

最後に

今回は僕の関心がある部分について書きましたが、本書はこれからソフトウェアエンジニアを目指す方にも非常に参考になる本です。むしろ、そういう方のほうが得るものが多いと思います。

技術書は面白いしタメになりますが、たまに技術から少し離れた本を読むのも面白いので、少しでも興味のある方はぜひ読んでみてください。

【Python3】__str__()と__repr__()は何を返すのが正解か

はじめに

こんにちは、SHOJIです。

本記事はPython3のログ設計を行っていた際に疑問に思った_str_()_repr_()は何を返すのがよいかの検討結果です。


すみません、ちょっと語弊がありました。検討結果というほどコレだ!というものには残念ながら行き着いていないです。

本記事はあくまで自分なりに検討した結果、これが良さそうかな?程度の暫定的な案です。

_repr_とは何か

repr() 組み込み関数によって呼び出され、オブジェクトを表す「公式の (official)」文字列を計算します。可能なら、これは (適切な環境が与えられれば) 同じ値のオブジェクトを再生成するのに使える、有効な Python 式のようなものであるべきです。できないなら、 <...some useful description...> 形式の文字列が返されるべきです。戻り値は文字列オブジェクトでなければなりません。クラスが __repr__() を定義していて __str__() は定義していなければ、そのクラスのインスタンスの「非公式の (informal)」文字列表現が要求されたときにも __repr__() が使われます。

この関数はデバッグの際によく用いられるので、たくさんの情報を含み、あいまいでないような表記にすることが重要です。

3. データモデル — Python 3.8.5 ドキュメント

_str_とは何か

オブジェクトの「非公式の (informal)」あるいは表示に適した文字列表現を計算するために、 str(object) と組み込み関数 format(), print() によって呼ばれます。戻り値は string オブジェクトでなければなりません。

__str__() が有効な Python 表現を返すことが期待されないという点で、このメソッドは object.__repr__() とは異なります: より便利な、または簡潔な表現を使用することができます。

組み込み型 object によって定義されたデフォルト実装は、 object.__repr__() を呼び出します。

3. データモデル — Python 3.8.5 ドキュメント

整理すると

_repr_()eval()で評価できるようなPython式に相当する文字列を返す。

_str_():表示用の文字列を返す。


よく使うstr()print()で呼ばれるのは_str_()の方です。

ただ、_str_()が定義されていなければ_repr_()の戻り値を返します。

動作を確認してみる

Counterクラスのインスタンスcounter)をprint(counter)で出力してみます。

1. _repr_()あり、_str_()なし

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

    def __repr__(self):
        return 'repr'

# start process.
if __name__ == '__main__':
    counter = Counter(1)
    print(counter)  # repr が出力される

オーバーライドした_repr_()の戻り値である'repr'が返されます。

2. _repr_()なし、_str_()あり

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

    def __str__(self):
        return 'str'

# start process.
if __name__ == '__main__':
    counter = Counter(1)
    print(counter)  # str が出力される

オーバーライドした_str_()の戻り値である'str'が返されます。

3. _repr_()あり、_str_()あり

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

    def __str__(self):
        return 'str'

    def __repr__(self):
        return 'repr'

# start process.
if __name__ == '__main__':
    counter = Counter(1)
    print(counter)  # str が出力される

オーバーライドした_str_()の戻り値である'str'が返される。※_str_()_repr_()より優先されます。

4. _repr_()なし、_str_()なし

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

# start process.
if __name__ == '__main__':
    counter = Counter(1)
    print(counter)  # <__main__.Counter object at 0x7fb4685c1c50> が出力される

_str_()がないので、_repr_()の戻り値が返されているはずです。

_str_()を定義して確認してみます。

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue
        
    def __str__(self):
        return self.__repr__()

# start process.
if __name__ == '__main__':
    counter = Counter(1)
    print(counter)  # <__main__.Counter object at 0x7fb4685c1c50> が出力される

_str_()では自クラスで未定義の_repr_()を返します。

この戻り値が「<_main_.Counter object at 0x7fb4685c1c50>」であることから、「_str_()なし、_repr_()なし」は親クラス(object)の_repr_()を返していると分かります1

_repr_()_str_()では何を返すべきか

Counterクラスで考える

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

    def increment(self):
        self.value += 1

    def get(self):
        return self.value

Counterクラスは、インスタンス生成時にvalueに初期値を設定し、increment()を呼び出すごとにvalueをカウントアップし、get()valueの値を返します。

_repr_()をオーバーライドする

_repr_()eval()で評価できるようなPython式に相当する文字列を返す。

これを踏まえて、Counterクラスのインスタンスと等価のインスタンスを生成できる文字列を返す_repr_()を追加します。

class Counter:
    def __init__(self, initialValue=0):
        self.value = initialValue

    def increment(self):
        self.value += 1

    def get(self):
        return self.value
    
    def __repr__(self):
        return '%s(%s)' % (self.__class__.__name__, self.value)  # Counter(1) を返す

_repr_()の戻り値を使い、eval()インスタンスを生成します。

# start process.
if __name__ == '__main__':
    counter = Counter()
    print('counter value:%s' % counter.get())   # counter value:0
    counter.increment()
    print('counter value:%s' % counter.get())   # counter value:1

    copy = eval(repr(counter))                  # counterと等価のインスタンスを生成
    print('copy value:%s' % copy.get())         # copy value:1

copyインスタンスが、一度increment()したcounterインスタンスと同じ1を出力しているため、期待通りの結果です。


ただし、これはCounterクラスがインスタンス生成時に初期値を設定できるから成立する話です。Counterクラスがインスタンス生成時に初期値を取らない場合、等価なインスタンスを作ることはできません。

その場合は「<_main_.Counter object at 0x7fb4685c1c50>」にならい、「<モジュール名.クラス名 object at 識別子>」がベターと思います。

def __repr__(self):
    return '<%s.%s object at %s>' % (self.__module__,
                                     self.__class__.__name__, 
                                     '0x{:x}'.format(id(self)))
# <__main__.Counter object at 0x7fb4685c1c50> を返す。

今回は親クラス(Object)で同じように出力できるのでわざわざ自クラスで再定義する必要はありませんが、継承する親クラスによっては上書きたいシチュエーションがあるのでコードを記載しています。

_str_()をオーバーライドする

_str_():表示用の文字列を返す。

どういう情報が欲しいか次第ですが、自分なら_repr_()の情報に加えメンバ変数の情報を付与します。

デバッグログを出力するときにインスタンスのメンバ変数を見たいことが度々あるので。

def __str__(self):
    return self.__repr__() + str(vars(self))
# <__main__.Counter object at 0x7fb4685c1c50>{'value': 1} を返す。

vars(self)を使うとすべてのメンバ変数をdictで取得することができます。

セキュリティの問題もあるので、実際にすべてのメンバ変数を返してよいかは個別に判断してください。


  1. Counterは何も継承していないように見えますが、Python3では何も継承しないクラスはobjectクラスを継承しています。

【読書感想文】初心者も中堅もプログラマはリーダブルコードを読もう

はじめに

こんにちは、SHOJIです。

本記事はプログラミング初心者向け書籍として超有名な「リーダブルコード」のレビューもとい感想文です。

www.oreilly.co.jp

僕はこの本がとても好きで定期的に本棚から引っ張り出しては読んでいます。

初心者向けとして紹介されることが多いですが、業務経験10年を超えるような方でも得るものがある本だと思うので、タイトルに「中堅も」と入れました。

リーダブルコードってどんな本?

「リーダブルコード ~より良いコードを書くためのシンプルで実践的なテクニック~」というタイトルが示すとおり、良いコードを書くためのシンプルかつ実践的なテクニックが載っています。


メソッド名や変数名といった名付けの仕方から始まり、読みやすくするための美しいコードのまとめ方、コメントの付け方、コードの分割の仕方等、すぐに使えてコードを書く上で重要なテクニックが詰まっています。


説明にはそれぞれサンプルコードがついているので、具体的にイメージしながら読み進めることができます。

僕は専門書を読んでも「なんとなく言いたいことは分かるけどイマイチ具体化できない」ということが多いので、例を提示して説明してくれるのは非常に助かりました。あと、文章が硬くないのもありがたいです……笑

目次と感想

目次

  • 1章 理解しやすいコード

  • 2章 名前に情報を詰め込む

  • 3章 誤解されない名前

  • 4章 美しさ

  • 5章 コメントすべきことを知る

  • 6章 コメントは正確で簡潔に

  • 7章 制御フローを読みやすくする

  • 8章 巨大な式を分割する

  • 9章 変数と読みやすさ

  • 10章 無関係の下位問題を抽出する

  • 11章 一度に1つのことを

  • 12章 コードに思いを込める

  • 13章 短いコードを書く

  • 14章 テストと読みやすさ

  • 15章 「分/時間カウンタ」を設計・実装する


1章は導入、2章&3章は命名、4章はクラス・関数のキレイなまとめ方、5章&6章はコメント、7章〜9章は読みやすい処理の書き方、10章からは複雑な処理を読みやすくするテクニック、という感じです。


章のタイトルから分かるように話の本筋はコードをキレイに書くことなので、扱っているプログラミング言語に関わらずタメになる内容になっています(とはいえ、オブジェクト指向言語を一つも触ったことがないと読みにくい部分があると思います)。


個人的には「3章 誤解されない名前」が気に入ってます。特にfilter()という関数名の曖昧さが指摘されているところ、読めばなるほどと納得できる内容ですが、僕としてはfilter()の時点でも十分に解像度の高い単語だと思うのでまだ考えが足りないなと反省しました。ただ、改善していこうと思う一方、英語ネイティブでないとここに書いてあるクオリティの名付けをしていくのは難しいかなという思いもあります。


あとは「5章 コメントすべきことを知る」の中の「ひどい名前はコメントをつけずに名前を変える」の部分、プログラマなら誰しも一度は見たことあるようなアンチパターンが取り上げられてて面白いです。そもそも、5章自体があるあるネタかってくらい既視感のあるアンチパターンだらけなので、どこを読んでも非常に面白いです。

最後に

本書はこういう方にオススメです。

  • 独学でプログラミングを勉強している方

  • ソースレビューで書き方の指摘を多く受けている方

  • 自分で書いたコードに読みづらさを感じる方

  • 後輩や部下のコーディング指導に悩んでいる方