suzukiyou blog

建築設計とかpythonとかその辺をとりあえずする

pythonで国立国会図書館のAPIを叩いて保存する

さっそくやっていきます。

スクリプトする。

#coding:utf-8
#samp.py

import urllib2
import codecs

if __name__=="__main__":

    oqfp=codecs.open("query.txt","w","utf-8")
    orfp=codecs.open("log.xml","w","utf-8")
    
    ndlurl=r"http://iss.ndl.go.jp/api/sru?operation=searchRetrieve&version=1.2&recordSchema=dcndl&onlyBib=true&recordPacking=xml"

    isbn="4876980438"
    query="".join([ndlurl,r"&query=isbn%3d%22",isbn,r"%22","%20AND%20dpid%3diss-ndl-opac"])

    oqfp.write(unicode(query))

    response=urllib2.urlopen(query)
    source=response.read()

    dec=codecs.getdecoder("utf-8")
    rdf=dec(source)[0].replace(u"&lt;",u"<").replace(u"&gt;",u">").replace(u"&quot;",u"\"")

    orfp.write(rdf)
    

叩く。

python samp.py

query.txtはこのような感じになる。

http://iss.ndl.go.jp/api/sru?operation=searchRetrieve&version=1.2&recordSchema=dcndl&onlyBib=true&recordPacking=xml&query=isbn%3d%224876980438%22%20AND%20dpid%3diss-ndl-opac

log.xmlrdf-xml形式でこう。

<?xml version="1.0" encoding="UTF-8"?>
<searchRetrieveResponse xmlns="http://www.loc.gov/zing/srw/">
  <version>1.2</version>
  <numberOfRecords>1</numberOfRecords>
  <nextRecordPosition>0</nextRecordPosition>
  <extraResponseData>
<facets>
  <lst name="REPOSITORY_NO">
    <int name="R100000001">1</int>
    <int name="R100000002">1</int>
  </lst>
  <lst name="NDC">
    <int name="5">1</int>
  </lst>
  <lst name="ISSUED_DATE">
    <int name="1997">1</int>
  </lst>
  <lst name="LIBRARY">
    <int name="佐賀県立図書館">1</int>
    <int name="名古屋市鶴舞中央図書館">1</int>
    <int name="国立国会図書館">1</int>
    <int name="大阪市立図書館">1</int>
    <int name="大阪府立中央図書館">1</int>
    <int name="岐阜県図書館">1</int>
    <int name="岡山県立図書館">1</int>
    <int name="徳島県立図書館">1</int>
    <int name="愛知県図書館">1</int>
    <int name="札幌市中央図書館">1</int>
    <int name="東京都立中央図書館">1</int>
    <int name="滋賀県立図書館">1</int>
    <int name="石川県立図書館">1</int>
    <int name="神奈川県立川崎図書館">1</int>
    <int name="福井県立図書館">1</int>
    <int name="秋田県立図書館">1</int>
    <int name="茨城県立図書館">1</int>
    <int name="香川県立図書館">1</int>
    <int name="鳥取県立図書館">1</int>
  </lst>
</facets>
  </extraResponseData>
  <records>
    <record>
      <recordSchema>info:srw/schema/1/dc-v1.1</recordSchema>
      <recordPacking>xml</recordPacking>
      <recordData>
<rdf:RDF xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:dcndl="http://ndl.go.jp/dcndl/terms/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <dcndl:BibAdminResource rdf:about="http://iss.ndl.go.jp/books/R100000002-I000002639920-00">
    <dcndl:catalogingStatus>C7</dcndl:catalogingStatus>
    <dcndl:bibRecordCategory>R100000002</dcndl:bibRecordCategory>
    <dcndl:record rdf:resource="http://iss.ndl.go.jp/books/R100000002-I000002639920-00#material"/>
  </dcndl:BibAdminResource>
  <dcndl:BibResource rdf:about="http://iss.ndl.go.jp/books/R100000002-I000002639920-00#material">
    <dcterms:identifier rdf:datatype="http://ndl.go.jp/dcndl/terms/JPNO">98048304</dcterms:identifier>
    <dcterms:identifier rdf:datatype="http://ndl.go.jp/dcndl/terms/ISBN">4-87698-043-8</dcterms:identifier>
    <rdfs:seeAlso rdf:resource="http://id.ndl.go.jp/jpno/98048304"/>
    <rdfs:seeAlso rdf:resource="http://iss.ndl.go.jp/isbn/4876980438"/>
    <dcterms:title>耐震構造設計論</dcterms:title>
    <dc:title>
      <rdf:Description>
        <rdf:value>耐震構造設計論</rdf:value>
        <dcndl:transcription>タイシン コウゾウ セッケイ ロン</dcndl:transcription>
      </rdf:Description>
    </dc:title>
    <dcterms:creator>
      <foaf:Agent rdf:about="http://id.ndl.go.jp/auth/entity/00092326">
        <foaf:name>山田, 善一, 1929-</foaf:name>
        <dcndl:transcription>ヤマダ, ヨシカズ</dcndl:transcription>
      </foaf:Agent>
    </dcterms:creator>
    <dc:creator>山田善一 編著</dc:creator>
    <dcterms:publisher>
      <foaf:Agent>
        <foaf:name>京都大学学術出版会</foaf:name>
        <dcndl:location>京都</dcndl:location>
      </foaf:Agent>
    </dcterms:publisher>
    <dcndl:publicationPlace rdf:datatype="http://purl.org/dc/terms/ISO3166">JP</dcndl:publicationPlace>
    <dcterms:date>1997.9</dcterms:date>
    <dcterms:issued rdf:datatype="http://purl.org/dc/terms/W3CDTF">1997</dcterms:issued>
    <dcterms:description>文献あり</dcterms:description>
    <dcterms:subject>
      <rdf:Description rdf:about="http://id.ndl.go.jp/auth/ndlsh/00572563">
        <rdf:value>耐震構造</rdf:value>
      </rdf:Description>
    </dcterms:subject>
    <dcterms:subject rdf:resource="http://id.ndl.go.jp/class/ndlc/NA93"/>
    <dcterms:subject rdf:resource="http://id.ndl.go.jp/class/ndc9/524.91"/>
    <dcterms:language rdf:datatype="http://purl.org/dc/terms/ISO639-2">jpn</dcterms:language>
    <dcterms:extent>420p ; 23cm</dcterms:extent>
    <dcndl:price>5200円</dcndl:price>
    <dcterms:audience>一般</dcterms:audience>
    <dcndl:materialType rdfs:label="図書" rdf:resource="http://ndl.go.jp/ndltype/Book"/>
    <dcterms:accessRights>S01P99U99</dcterms:accessRights>
  </dcndl:BibResource>
</rdf:RDF>
      </recordData>
      <recordPosition>1</recordPosition>
    </record>
  </records>
</searchRetrieveResponse>

適当にxml.etree.ElementTreeなどを使って読むべし。

文書マネジメントに関する件

あけましておめでとうございます。
技術文書マネジメントに関するいろいろな技術例を見ていきます。
主にJIS Z 8245-1を見ていくこととします。

問題点の確認

文書を大量に扱うので、書籍・pdf・jpg・dxf等の様々なデータ(紙・電子データ混用)を適切に記録していかないとはかなくなります。
今まで超整理法っていうか「野口式押しだしファイリング」で、記録日をファイル名(およびプロジェクト名)をファイル名として共用ファイルに適当にぶち込んでおいたのですが、年末転属があり、引き継ぎをする羽目になってかなり死にました。死にたくないですね?

超整理法はスタック式管理のため、長期保存に向かない。例えばコンパイラ本には「統計的に、生存期間の短い変数はとことん短く、長い変数はとことん長い」と書いてあり、長い変数は参照を用いてヒープ領域に持っていく、ということがおこる。文書管理はとかく人力でやるので、どれが生存期間が長い変数なのだかよくわからんし(というか全部長い気がする)ヒープに持っていくその度ごとにアドレスを設定する(適切なフォルダに配置する)の、面倒くさい!やりたくない!

かと言ってgit的なリポジトリの運営は難しい。確かにプルしてマージ、コミットしてプッシュするのは有効、でもそれは「文書やコードの構造を理解していないと闇雲にファイルを追加してしまう」「文書の構造設計が完了している段階でなければ実質的には運用できない」という問題がある。やはり超整理法は必要です。

超整理法的な「スタック」文書管理とgit的な「バージョンによる」文書管理を同時に運用しなければなりません。しかしそれらは別物ですから、その間を埋めるなんらかの方法が必要です。

予想と適用する技術領域

超整理法

スタックの方向では、基本的に超整理法を行います。それぐらいだったら俺でも人力でも出来るという実績があるからです。
「超」整理法1 押出しファイリング (中公文庫)
「超」整理法―情報検索と発想の新システム (中公新書)
などでいいでしょう。
具体的には、スタック用フォルダ"%desktop%\stack\"をデスクトップにでも作って、ファイルには"YYMMDD_projectname_contents.sufix"という名前をつけてぶち込む。以上。

IT系バージョン管理

俺が既に把握している技術としてのバージョン管理は、git的なものと、.NET assembly的なものがあり、それぞれで思想が異なる。
俺の認識ではgitはテキストベースのファイルをdiffでどうにかするものだという認識があります。git上の管理においてはバージョン番号(ex .NET assembly例で、major.minor.build.revision)が明確に表現されていない、という認識がある(本当かどうかはわからない。多分うまいことやってるところもあるでしょう)。
.NET assemblyのような形式で、実際の物理ファイルとは別個にメタデータをもつという方が、文書のライフサイクルを考える上では有利という気がしますね。管理ファイルがテキストファイルに限定されないという点、発行の概念がある点などが有利、と思われる。その他.NET Frameworkでの思想には見るべきとところが多い。IL(中間言語)やメタデータの分離、メタデータの記述、公開鍵/秘密鍵によるセキュリティ等はそのまま文書管理においても使えそうな雰囲気がある。

参考

標準組織系文書管理

別の思想としてISO9001系の品質管理マネジメントシステムがあり、その辺なんかあるんじゃねーのと思いながらこの度よくよく調べると一連の規格があり、参照できそうな雰囲気がある。
参考
日本規格協会 標準化教育プログラム 電気電子10 技術文書 -文書作成・マネジメント-PDF

参照するのは、以下の規格です。
JIS Q/Z系

JIS C系

ISO 10303[STEP]

もともとIEC(国際電気標準会議)で文書マネジメントの考え方が出てきたらしく、歴史的な経緯からJISにも電気系が多い(というかIECの翻訳)のだが、オブジェクト指向に関してはどの分野でも適用可能と思われるので参考となる。一方電気系の出自の都合、配線だかブレーカだかの例が多いのは、まあ仕方ないっていうか……

文書分類ということで言えばZ8245-1とC0452-2でオブジェクト指向的に分類していけ、またC0454に従ってツリー状に配置していけ、というのが世の考えらしい。またライフサイクルについて言及があるのはZ8245-1である。メタデータ(索引的なもの)に言及があるのはZ8245-1だが、保存・台帳作成に当たってのダブリンコアメタデータについての言及がZ6017の附属書Cにある。

図書館系書籍管理

あとはこう、文書あるいは書籍、管理対象に対する目録作成・帳票作成のあたりでは、図書館系でやってることが参考になるかもしれない。ISBNとかから書籍データを取ってくる、とかいうような既知の技術があります。思ったよりいろいろな書籍データがwebで供給されているのだが、ダブリンコアメタデータと呼ばれるものを利用しているらしい。データ形式が規定されているので、これを参考にしてフィールドを作れそうな気がするから、リンクを貼る。

歴史的なところは置いておくとして、いろいろな組織がいろいろなダブリンコアメタデータ形式を作成しているというのが実体らしい。
日本では国立国会図書館のDC拡張記法DCNDLがあり、例えばISBNをキーとしてURLクエリでAPIを叩けば必要なデータが取得できる。
技術としてはXMLによるRDF記述を行っており、つまりXMLパーサで処理できるようだ。

検討事項

技術文書マネジメントシステムを構想していく前に、検討すべき事項が何か調べていく。

  • 文書の分類
  • 文書の構造化
  • 文書のライフサイクル
  • 文書のバージョン
  • 文書メタデータ

分類

標準組織型分類、JIS系に文書種類分類コード(DCC)がある。これはビジネス文書の分類が念頭にあるのでこれを見ていく。一応、図書館系の図書分類法というのがあるが、一般書籍の分類を念頭に書かれているので、ビジネス文書の分類としては不適です。国際的には国際十進分類法UDC、デューイ十進分類DDC、国内的には日本十進分類法NDC、国立国会図書館分類法NDLCがメジャーらしい。(図書分類法 - Wikipedia)

DCCの書式はJIS C 0451で諸々書かれている。
&(A1)(A2)(A3)(文書種類計数番号)でそれぞれ

  • A1:技術分野の表示
  • A2:文書種類主分類の表示
  • A3:主分類に大して個別に定義される副分類の表示

であり、後続文字の追加については自由であるとされている。

規格の趣旨としては4.1文書種類の分類一般で以下のようにあるので理解しておくべき。

文書種類の名称は、様々な表現が使用され、それらのうちの多数は標準化されていない。しかし、特定の使用者グループの間ではよく知られていることがある。さらに、文書種類が同じでも、異なった使用者グループでは異なった名称を用いている場合もある。そのため、文書種類の名称を使用することは、異なる団体・組織間のコミュニケーションには不適切である。
団体・組織間で授受される文書の共通の理解を得るため、文書種類分類コード(DCC)をこの企画で規定した。このコードは、文書種類の名称が定義又は規格化されていないことに関係がなく、情報の内容を理解する基準となる

つまり、よそ者とのコミュニケーション時にDCCを参照しなさい、規格で決めているから意味がわかるでしょう、と言った感じのものだ。自分が管理するためにDCCをつけるのではないですよ、ということです。実運用段階で直で使うにはレベルが高すぎてわけわかんなくなりそう。例えば異なるDCCをつけてしまうという懸念がある。しかしISO9001のような文書マネジメントシステムとしてDCC分類を行った場合には分類の効果があると思われ、文書マネジメントシステムで規定するべき事柄であるという印象がある。

附属書Aに(規定)分類記号が定義されていてA1については下のようになる。
(注:掲載する表は手で写しているのでなるべくリンク先を参照されたい)

DCC A1 技術分野
A 全体管理
B 全体技術
C 建設エンジニアリング
E 電気技術(制御・情報・通信技術を含む)
M 機械エンジニアリング(通常プロセスエンジニアリングを含む)
P プロセスエンジニアリング(Mとの区別が必要な場合)

A2についてはおおよそ以下のようになる。

DCC A2 概要
A 文書化記述文書
B 管理文書
C 契約および非技術文書
D 一般技術情報文書
Q 品質マネジメント文書及び安全性記述文書
T 幾何学的正常記述文書
E 技術要求及び寸法文書
F 機能記述文書
L 位置文書
M 接続記述文書
P 構成品リスト
W 運転手順及び記録

で合わせて書くと下のようになる。

DCC A2 DCC A3 文書種類分類 情報の内容 文書種類の例
A A 総括文書 内容及び関連について一般文書に優先する管理文書 表紙・目次
A B 文書に関する一覧表 文書の内容を示す文書 文書一覧表・索引
B A 登録者 ビジネスパートナー・顧客・コンサル等の情報 ベンダーリスト・供給者一覧表・配布物一覧表
B B 報告書 管理に関する情報など 打合報告・状況報告
B C 往復書簡 書簡のようなもの 書簡
B D プロジェクト管理文書 アクティビティーに関する情報 文書交換リスト・作業時間計算表
B E 資源計画文書 時間・要員・材料の計画情報等 工程表・資源投入図表
B F 発送・保管・輸送文書 商品の発送に必要な情報 発送仕様書・発送リスト
B G 現地計画・現地組織文書 現地の構成情報等 要員の現地要件
B H 変更に係る文書 変更に関する文書 変更通知書・変更要求書
B S 安全性文書 安全計画等 消火防護計画書等
B T トレーニング仕様文書 トレーニング計画に関する文書 トレーニング説明書
C A 引合、計算、申込、検収の情報 同左 引合書・落札内示書・検収通知書
C B 承認用文書 承認・委託等の情報 適用承認書・承認許可書
C C 契約文書 契約の内容情報 契約書・検収完了書・受け渡し条件
C D 発注及び納品文書 発注情報 注文書・貨物引渡通知書
C E 送付文書 送付情報 送り状
C F 保険文書 保険情報 保険契約書・損害評価表
C G 保証文書 保証情報 保証証明書
C H 専門技術知識 専門家の意見等 専門技術資料
D A データ文書 仕様書的なもの データシート・寸法図・仕様書
D B 説明文書 システム・他の文書の技術的説明書 システム説明書・文書化構成説明書
D C 指示書およびマニュアル 製品等の取扱・据付説明書 製造指示書・据付指示書・検査指示書・取扱説明書
D D 技術報告書 技術に関する一般的所見情報 技術報告書・研究開発報告書
D E カタログ掲載文書 製品・サービスの範囲に関する情報 カタログ・リーフレット
D F 技術刊行資料 刊行物の形で技術内容の一般情報を示す文書 技術刊行物
E A 法的要求文書 技術制限・当局許可等 法令
E B 規格及び規制 標準化組織による指針 IEC・ISO・JIS
E C 技術仕様・要求文書 顧客要求を満たす適切な装置等の設計と引渡に必要な情報 要求仕様書・技術仕様書
E D 寸法文書 データ類の仮定値に関する情報 計算シート(技術の)
F A 機能全体文書 図示の形でシステムの機能・構造を全体的に表す文書 全体図・ネットワーク・ブロック線図
F B 流れ線図 システムの手順・流れなどの情報 ブロック線図・配管計装線図・フロー図
F C MMI配置文書 マンマシーンインターフェースの配置を示す文書 表示板配置図
F E 機能説明 システム等の機能的動作に関する情報 機能説明
F F 機能図表 機能的動作を優先順に示す線図 論理機能線図・シーケンス図
F P 信号説明 機能ユニットの入力または出力として定義される信号の情報 信号リスト
F Q 設定値文書 設定値等の情報 設定値リスト
F T ソフトウェア仕様文書 ソフトウェアに特定の情報を提供している文書 プログラム線図・コードリスト・設計説明書
L A 開発・調査文書 道路・インフラ・建築地の調査情報 土地計画図
L B 土木・基礎工事文書 建設地での土木工事・基礎工事に関する情報 掘削計画図・基礎図
L C 建物骨組文書 構造物の位置と特性に関する情報 配筋図・静荷重図
L D 現地位置文書 現地据付市に関する情報 据付図・配置図・ケーブル経路図
L H 建造物内位置文書 建造物の位置に関する情報 建築図
L U 機器内位置文書 キュービクル・盤等の構成部品の位置に関する情報 QB組立図・盤組立図
M A 接続文書 部品・組立品の物理的接続についての情報 ユニット接続図・端子接続図
M B ケーブルまたは配管文書 現地におけるケーブル・配管敷設に必要な情報 ケーブル線図・配管リスト
P A 材料リスト 主に据付調整に必要な資材の情報(ボルト・ネジ・工具・計測器)など 材料リスト
P B 部品リスト 対象物の交換に保管する部品情報 部品リスト・予備品リスト・ラベルリスト
P C 品目リスト 数量を特定せずに製造に必要な部品等を示す文書 品目リスト
P D 製品リスト及び製品タイプリスト 製品のタイプについての情報 製品リスト・製品タイプリスト
Q A 品質マネジメント文書 品質保証活動に関する文書 試験合格証・材料証明書・試験成績書・監査記録・不適合リスト・適合宣言
Q B 安全性記述文書 要員・使用者の人命健康、環境等についての危険や損害防止に関する情報を示す文書 安全性検討・危険度評価
T A 計画図 計画または構想段階における対象物の情報 概念図・設計図
T B 構造設計図 最終段階での対象物の情報を示す文書 寸法図・取合図・分解図
T C 制作及び組立図 制作及び組み立てに必要な情報 製作図・穴あけ計画・溶接計画
T L 配置文書 構成部品の配置に関する情報を示す文書 配置図
T Z 運転手順及び記録 システムの運転期間中の設定値等の記録 運転記録
W A 設定値文書 プロセスの運転に関する設定値情報 作業処方書
W T 履歴記録簿 特定の活動中のイベントの定期的な記録 運転履歴記録・保守点検記録

附属書Bに「確立された文書種類」というのがある。例えば「AA:表紙」「LH:建築図」「QZ:監査記録」などが提示されている。これらは個別にJISやISOやIEC規格があったり、慣習的によく知られているものである、とされている。附属書Bでは確立された文書種類の最低限の情報内容、含まれうる情報要素の例が書かれています。

感想としては、マスター性の文書と、プロジェクト性の文書が混在しているよなーという感じがする。AA総括文書などはマスターの文書の一覧を示す文書とプロジェクトの文書一覧を示す文書の両方があったり、DAデータ文書はマスター性の文書ですが、同じものをプロジェクトに適用するとEC技術仕様/要求文書になってDDCが変わったりする。これらの仕分けをする必要があるんじゃないか?という気持ちがある。

構造化(および参照指定)

JIS C0454を見ると、文書及びオブジェクトの階層構造化ガイドラインが示されています。序文には以下のように書かれている。

この規格は、次によって、システムの構造化原則と文書の構造化原則とを関連付けることが出来る。
-主文書を用いた製品構造の情報・文書の体系化による、製造業における共通する業務の標準化
-技術的オブジェクトの一つの文書群において、補文書と明確に関連付けられる主文書の一般的概念を確立することによる、JIS C 0451の6.で示す指針の細目化および形式化
-文書の構造化における、JIS C 0452-1の構造化原則によるオブジェクトの概念の適用。幾つかの観点を持ってオブジェクトが系統的な方法でまとめられる点で、これまでの規格の範囲を超えている。

「システムの構造化原則(JIS C 0452-1)」と「文書の構造化原則(JIS C 0451)」を関連付けることが出来る、と書いている。この点については後で説明するとして、とりあえず文書の構造化については、「文書には文書構造があり、『識別部分』『仕様書部分』『改訂部分』『管理部分』がありますね(4.3.2)」「文書には主文書および補文書があり、分割されえますね(5)」「主文書は補文書を引用していますね(5.1)」のようなことが書いている。まあそうでしょう。そのとおりです。

システムの構造化原則についてはJIS C 0452-1を読む。
文書に書かれているのは物であって、ものの一意な指定をしたい。という気持ちでJIS C 0452-1を読むとそう書いてある。参照指定というのがそれ。
「オブジェクトの性質やら何やらについてツリー的構造を持たせて分類できますね?」ということが書かれているのが重要。まあ参照指定はともかくとしても、「建屋」の「空間」の「照明」の「スイッチ」の「型式」、「建屋」の「境界」の「壁」の「ドア」の「耐火構造」などというように、このオブジェクトをつなぐ「の」をドットに変えれば、おおなんかメソッドチェーンじゃん、みたいな感じがありますね?あれ。
JIS C 0452-2ではオブジェクトの目的またはタスクに対するオブジェクトの分類記号を定義している。例えばC:材料、エネルギー又は情報の保存<記録Recording><貯蔵又は保存Storing>には例としてタンク・コンテナ・蓄圧器・コンデンサ・ハードディスクなどが例示されており、これを用いてオブジェクトに記号を振っていくと、ツリー状の構造を自然に構成できますね?と書いてある。

こういう思想でSTEPとかifc(-xml)などが作られているのだなぁ、という気持ちがあります。ifcはBMIの書式の一つですが、詳しくはHome — Welcome to buildingSMART-Tech.orgを参照のこと。オブジェクトを構造化したいという気持ちがあり、ifcではオブジェクトをツリーとして表現します。ifcは異なるCAD間でのBMI記述の交換を可能とするものだと位置づけられていて、ifcファイル1つを渡すことで十分な情報を与えられるようにしましょうというものです。

個人的には、文書は主文書と補文書に分けて管理しましょうと言ってて、一方でオブジェクトは1ファイルで管理しましょう、と言っているような気がして、それどうなのです?矛盾しているのでは?と感じる。
運用においては文書とオブジェクトの差については注意が必要。例えば改定について、文書が改定されるのと、オブジェクトが改定されるのは確かに同じようなものです。しかし、オブジェクトの改定は文書の改定をもって記録されるわけで、オブジェクトの改定をオブジェクト自身に記録するわけにはいかない。文書は適当なフォルダにまとめれば簡単にリストが作れるが、一方でオブジェクトはそうではない。また文書からオブジェクトに対してのリンクは貼られるが、一方でオブジェクト側から文書にリンクすることは無い。このような差があるので、一般的に文書とオブジェクトの統一が出来るわけじゃないでしょう。
だいたい、一貫性の管理、人間じゃ無理では?人間がやったら絶対コミット漏れする。文書だけ更新してオブジェクト更新できてないとか間違いなく起こる。そういうようなDBを用いてモデリングするしかなくないですか?という思いがあります。

またJIS Z 8245-1では文書及びメタデータのある文書タイプが挙げられている。
単体文書、複合文書、集合文書、文書セットの4つであり、以下引用のように書かれている。
ちなみに「集合文書」は「文書集合」とも書かれている箇所があり規格上で表記にゆれがある気がする。3.2.6定義部分では「集合文書」の表現で定義されているようだ。

4.3.1 単体文書 個々の文書は、メタデータに関係づけられている。(略)
さらに、この規格では、次により包括的な構造をサポートしている。
4.3.2 複合文書 文章は、結果としては2つ以上の種類の文書から構成されたものになる。例えば、技術仕様文書は、テキストファイル及び/又は画像的表現のファイルからなる。個々のファイルは、異なったソフトウェアアプリケーションによって作られる場合もある(略)。結果としての文書からは、それの前段階のプロセスはわからない。
複合文書に含まれる他文書とのリンクのマネジメントについては4.4を参照。(略)
4.3.3 文書集合 文書集合は、それぞれがそれ自身でメタデータとの関連付けを持っている独立した文書の集合である。文書集合はメタデータをもつが、必ずしも自身の単独の文書をもつ必要はない。(略)
備考 文書集合には、何がどのように集合しているかの"レシピ"が含まれている。このレシピは、文書集合のメタデータ又は文書自体の一部である。
4.3.4 文書セット 文書セットは、それ自身のメタデータを持つ。そのメタデータは、文書に含まれている文書のリストだけでなく文書セットの目的が記述されている。文書セットに含まれる各文書は、それ自身のメタデータを持っている。(略)
4.4 リンクされた文書 作成段階の文書のバージョンは、その構成要素となっている他の文書などに連結するリンクをはり付けてもよい。しかし、文書のバージョンが、例えば、承認及び発行のためにバージョン管理下に入る場合(すなわち、内容が固定化される場合)は、連結するリンクは許されない。能動的に変化するリンクによってバージョンの内容が変更してしまうからである。
備考 能動的に変化するようなリンクを持つ文書は、製造物責任などに関する問題が生じる可能性があることに注意を要する。

文書構造の類形とそのメタデータの張り方を規定した物となっているが、以下の表のようにまとめられるであろう。

文書類形 本文の有無 自身のメタデータ(バージョン)を持つ 構成要素文章を持つ 構成要素文章がメタデータ(バージョン)を持つ
単体文書 × ×
複合文書 ×
集合文書 ×
文書セット

単体文書以外ものに関しては他の文書を構成要素としてそれにリンクを貼るということが許される。しかしリンクを貼る際には構成要素文章がバージョン管理されているかどうかを注意する必要があるのだ、ということを書いています。バージョン管理されているということは下のほうでも書きますけどある目的に対する文書の「発行」を意図しているということを意味する。そこで発行につきまとう責任問題のパターンを分けるために「複合文書」と「文書セット」の差があるのだと読める。
集合文書はメタデータを持っている複数の文書を取り扱うための「フォルダ」めいたものだ、と考えられるが、発行を意図していないので構成要素文書はバージョン管理化のものでなくても良さげだなあ、と読める。マスターデータとかは実際発行されないので、そういう文書群は集合文書ですね。

ライフサイクル・成熟度

JIS Z 8245-1「技術文書マネジメント-第一部:原則及び方法」の適用範囲を見ましょう。

1.適用範囲
この規格は、オブジェクトに関係する文書をそのライフサイクルを通じてマネジメントするために必要なメタデータを定義する原則及び方法について規定する。ここで言う文書ライフサイクルとは、ある文書の概念的な着想の段階から論理的・物理的に削除されるまでの期間をいう。ここで規定する原則及び方法は、すべての文書マネジメントシステムの基礎となる。
この規格は、すべてのアプリケーション分野における基本規格であり、かつ、第2部(備考1参照)に対して適用できる枠組みを規定する。(略)
4.3 文書の概念
ここに示す文書の概念は、従来の紙による文書だけでなく、1単位(情報が格納された一つの容器)として扱われるコンピュータベースの情報も取り扱う。この単位で、識別、構成、処理、管理、交換及び伝達される。
この規格において文書は、単体文書、複合文書、集合文書又は文書セットのいずれかになり得る。
例を、次に示す。
‐テキスト文書、例えば、文字による記述又はメッセージ。
‐グラフィカル文書、例えば、製図、絵画、図形、図表
‐リスト、例えば、部品リスト。
ハイパーテキスト文書、例えば、SGMLXML、HTML上にリンクされた文書。
‐マルチメディア文書、例えば、テキスト、画像、ビデオ、音声を合成したもの。
‐電子情報パッケージ(バスメッセージ)、例えば、クエリーメッセージ、自動ログメッセージ。
‐CAxモデル、例えば、CAE、CAD、CAM、多観点のモデル。

まずJIS Z 8245-1の規格の意図を説明すると、上のような感じで、結構包括的な規格なんですね、と言った感じ。媒体、文書の複合性等を包括する。
文書のライフサイクルというのがあり、それは着想から削除までの期間と規定する。それをマネジメントするという意図がある。
具体的にはライフサイクルを6.1で以下のように分類している。

No. ライフサイクル 活動例 管領 アーカイブ(長期保管領域) 管領域活動例
1 着手 検索・再利用・識別・分類・目次 × × なし
2 作成 編集・検索・再利用・半自動生成・回覧・参照・共同作業 × 検索・取出・閲覧・削除
3 確立 回覧・調査・統計・承認・発行 × 同上
4 使用 通知・購読・配布・全複写・部分複写・代替フォーマット提供・情報媒体提供・閲覧・内容分析 検索・取出し・閲覧・削除・フォーマット更新・代替情報媒体提供
5 改定 着手・検索・全面改訂・校正・記述・協調 同上
6 廃止 着手・検索・協調・承認・廃止・ファイル履歴・取出 同上
7 削除 着手・検索・協調・承認・消去(削除) × × なし

また文書のライフサイクルにおいて、活動に応じて成熟度が上昇していく。成熟度が上昇する際に「検討用」「設計用」「承認用」「決定版」「回覧用」「改定版」「完成版」などの発行目的に対応するバージョンがあり、バージョンによって管理される、というモデルとなっています。

バージョン

JIS Z 8245-1の4.5「文書のバージョン」では以下のように書かれている。

4.5 文書のバージョン
4.5.1 一般 文書を使用及び/又は処理する限定された環境の中では、新しい文書のバージョンの発行基準を定めなければならない。一般的に次の2種類の変更が発生する。
a) 情報の更新
b) 情報の可視的な表現の変更
発行された文書のバージョンの基礎となる情報が変更される場合、文書のバージョンを新しくしなければならない。
文書の表現の変更の場合は、必ずしもバージョンを新しくする必要はない。
4.5.2 バージョンの有効性 文書のバージョンは、一つ又は複数の定められた目的のために発行することが出来る。文書のバージョンのそれぞれの目的には、有効となる時期及び期間、すなわち、バージョンの有効性を宣言する。目的とともにその有効性が変わった場合は、新しいバージョンを作成せずに、目的を変更してその有効期間を延長してもよい。
4.5.3 連続的に有効性が遷移するバージョン 連続的に有効なバージョンを更新する場合、最新に発行された文書のバージョンが唯一効力を持つ。すなわち、新しく発行されたバージョンは、同じ文書のバージョンが発行される場合、"取って代わる/取って代わられる"という双方向の関係が新旧のバージョン間で確立されなければならない。先行のバージョンのメタデータに、それが後続のバージョンによって取って代わられることを記述する。また、後続のバージョンのメタデータに、それが先行のものに取って代わることを記述する。(略)
4.5.4 同時に複数有効性が存在するバージョン 同時に有効なバージョンが複数存在する方法が適用される場合、幾つかの発行された文書のバージョンが同時に有効である。すなわち、新しく発行された文書のバージョンは、同じ文書の以前に発行されたバージョンに自動的には取って代わることはない。
バージョンのそれぞれの決められた目的は、その目的の明確な終了、すなわち、決められた有効期限までは有効である。

ということで、文書は文書の発行目的の変更に伴って、バージョンを変更しなさい、ということですね。いろいろな文書があり、その中にはライフサイクルが長くて改定されうるものや、短くて改定されないもの、日毎に変わるので改定もクソもないものなどがありますが、多分文書タイプに応じた付番をつけとけばいいでしょう。長いものは.NET形式、短いものは日付管理とかそういう感じ。

一方で、文書が異なる(DCCが異なる)場合は、バージョンは一般に一致することはないでしょう、ということです。もちろん文書に対するバージョン管理だからこれでいいのだが、ここでオブジェクトの細々した変更はそれお前バージョン管理できるのかよ、という気持ちがある。また、有効期限とライフサイクルの関係も注意する必要がある。

ついでに.NET Frameworkのバージョンの付け方の指針も確認しましょう。めんどくせぇので詳細は省きますが、.NET Framework(Microsoftの共通言語基盤CLR)上ではネイティブの実行ファイル(PE)単体はなく、少なくともアセンブリのような実行コード(IL)とIL内のクラスなどの記述を含んだメタデータがセットとなったモジュールがあります。一つ以上のモジュールをまとめて一つの名前・バージョン・カルチャ・署名(これらをまとめてマニフェストという)をつけると一つのアセンブリという単位のまとまりが出来る。アセンブリに対して、CRLは別のプログラムをリンクしたりいろいろ出来る。署名をすると、共有可能なアセンブリとなります。(署名をしなくても使えることは使えるが同一ディレクトリなどに制限される。)共有アセンブリに対するリンクでは、CLRがバージョンチェックをしてくれるのでDLL地獄にならない、というよさがあります。
アセンブリマニフェストのバージョンの形式は、メジャー番号.マイナー番号.ビルド番号.リビジョンです。だいたいのパッケージのバージョンでは、メジャー番号は後方互換性がない場合に増えて、そうでないときはリリースごとにマイナーバージョンが増える。微妙なパッチとかバグフィックスの場合はビルド番号やリビジョンが増える。

有効期限とライフサイクルに関して、例。

  • ある機械製品があり、複数の部品の組み合わせで出来ている。
  • 製品自体の仕様書があり、複数の部品a,b,cの仕様書と、部品リスト・組立図をまとめた製作用図書がある。

この製品について以下のように文書を発行していくことを考えよう。
1)この製品をプロジェクトに用いることになり、要求仕様を提示することになった。
2)プロジェクト中に要求される製品の仕様の変更があり、それにともなって部品aが変更になった。
発行すべき文書およびそのバージョンを考える。マスター、初版発行後、改定後の文書とバージョンを考えると以下のようになる。

マスター文書 マスターDCC マスターバージョン 初版文書名 初版DDC 初版バージョン 改定後バージョン
× × × 文書表紙 MAA 1 2
製品文書構成リスト MDB xxx 要求仕様文書構成リスト MAB 1 2
製品仕様書 MDA xxx プロジェクト用製品要求仕様書 MEC 1 2
製品部品リスト MDC xxx プロジェクト用部品リスト MPB 1 2
製品組立図 MDC xxx プロジェクト用組立図 MFA 1 2
部品a仕様書 MDA xxx 部品a仕様書 MEC 1 2
部品b仕様書 MDA xxx 部品b仕様書 MEC 1 1
部品c仕様書 MDA xxx 部品c仕様書 MEC 1 1

まずマスターデータ文書からプロジェクト時の製品仕様要求文書を作る際に、文書種類分類コードが変更されて、別の文書となり、バージョンを1から取り直す事となる。この時プロジェクト文書からマスター文書への参照を張っておいたほうがいいが、マスターデータの有効性は消えない。
改定時は、部品b,cについては有効なので生きてるが、その他の改定前プロジェクト文書は無効としなければならない。また、製品要求仕様書以下は文書リストによって参照されるが、文書リストの参照は有効になった改定後バージョンの文書を参照するようしなければならない。

あと細々ですけど、作成段階においては作成者が、承認段階においては承認を要する(いくらかの)組織内で、発行段階においては複数の組織内で通用するバージョンが必要になるということが有ります。.NET方式でいいんじゃねえかな。

  • major ver.->発行バージョン
  • minor ver.->承認用バージョン
  • build ver.->作成者バージョン

くらいの雰囲気とか。

メタデータ

メタデータの内容

これもJIS Z 8245-1で定義されているものを参考にする。

まず指針としては5.使用環境に関連した文書のメタデータにかかれていて、おおよそ以下の注意がある。

  • 文書ライフサイクルに関連したメタデータがある
  • オブジェクトを作り出すビジネスプロセス(製品ライフサイクル)に関連したメタデータがある。
  • ビジネスプロセスを運用している組織の一般的知識ベースの生成維持管理に関連したメタデータがある。
  • あるプロジェクトの中での製品に関する情報を示すメタデータは文書のメタデータには含めないほうが良い。

文書ライフサクル内の活動に関連したメタデータについては、各ライフサイクルにおいてメタデータに含めるべき情報の例が6.に書かれている。

  • 着手段階
    • 識別用
      • 組織をもととした文書識別
      • 国際文書ナンバリングシステム、例えばISBN、ISSN
      • IDDNなどのデジタル出版物の国際的な識別子
      • 国際商品コードシステム、例えばJAN/EAN/UPC
    • 分類用
      • 契約上の識別子ならびにパートナーである組織及びその役割
      • 作業指示書の識別子
      • プロジェクトの識別子
      • 所有者、著者及び関連組織のデータ
      • 文書識別システム
      • 文書の役割
      • 文書の内容を示す文書の表題
      • 文書で使用する言語
      • 記載されたオブジェクト(への参照)
      • 発行日、有効期限
      • 作業分類体系における特定のノードとの対応
      • 文書化体系における特定のノードとの対応
      • 文書分類システム
      • 文書の作成に使用する国際規格、地域規格、契約文書のリストへの参照
      • 内外の承認用・製品検査用の仕様書として利用する文書リストへの参照情報
      • 文書のバージョン履歴(置換・更新)
      • セキュリティ等級
      • メタデータ及び関連文書内容へのアクセス権
      • 国家的、地域的又は組織的な契約で定めた譲渡制限
      • 契約又は業務指示書で規定された利用上の権利又は責任
      • 著作権特許権等の権利保護
      • 適用する評価及び承認手続き
      • 複数の言語によって表現された同一の情報を持つ文書がある場合は、原典の識別
      • 電子文書の作成に使われたテンプレート及び出典の識別
  • 作成段階
      • 成熟度
      • キーワードリスト
      • 抜粋又は要約
      • 文書の出典
  • 確立段階
    • 承認用
      • 作成者、送付日、要求日
      • 調査者、調査日、調査手順
      • 調査時コメント
      • 承認者、承認日、承認手順
      • 承認時コメント
    • 発行用
      • 作成者、送付日、要求日
      • 発行者、発行日、発行手順
      • 発行する文書バージョンの有効性
      • 発行目的
      • 発行目的と関連する製品のバージョン、ビジネスプロセスへの参照
      • 発行時コメント
  • 使用段階
      • 文書の使用実績
    • 配布用
      • 配布リスト、配布先リスト
      • 受信先の識別、住所とかメールアドレスとか
      • 関係者の役割
      • 配布リストへの申込
      • 物理的送付の場合の配布フォーマット仕様
      • 配布内容の一部である文書セットのバージョン
      • 発送作業の識別
      • 受取証
      • 参照した文書のバージョンのアクセス履歴情報
    • 閲覧用
      • 文書のバージョンにアクセスするのに必要なすべてのデータフォーマットに関する情報
  • 改定段階
    • 内容改定用
      • 新しいもののもとになった文書のバージョン
      • 他の文書のバージョンとの関係、置換又は影響
      • 変更責任者
      • 改定内容
      • 改定日
      • 変更の理由及び変更指示に関する事項
    • 発行目的の改定、廃止
      • 文書のバージョンの相互関係の履歴(取って代わる/取って代わられる)
      • 変更責任者
      • 改定内容
      • 改定日
      • 変更の理由及び変更指示に関する事項
  • アーカイブ段階
      • 保管期限
      • 書込アクセス権
      • 書込セキュリティ等級
      • 使用したソフトウェアおよびバージョン
      • 使用したプロセッサおよびバージョン
      • 使用した圧縮ソフトおよびバージョン
      • 使用した暗号化ソフトおよびバージョン
      • デジタル署名の使用有無
      • 記録媒体に応じたデータのリフレッシュ周期
      • 関連データを伴う物理的搬送媒体の更新履歴
      • フォーマット更新履歴
      • システム変更履歴
      • アクセス履歴
      • データ媒体の物理的な場所
      • 論理アドレス、パスとかファイル名とか
      • 内部索引リスト
  • 削除段階

メタデータの形式

ビジネス文書のメタデータ項目としては上記の項目ぐらいで問題ないと思うが、メタデータの電子形式は特段規定されてない。.xmlや.configを利用すれば良いでしょう、という気分ですが、この辺は図書館系のダブリンコアおよびその発展系を見て、そういう雰囲気で作ると楽かもしれない。

図書館系メタデータは、ダブリンコアおよびその拡張がよく使われている。
まず(シンプル)ダブリンコアというのがあり15の項のものがDublin Core Metadata Element Set(DCMES、ISO15836)で規定されている。さらにより細かい情報を定義できるような拡張プロパティおよび符号化スキームが追加されてこれがDCMI Metadata Terms(DCterms)が公開された。また国立国会図書館でもっと細かい書誌情報プロパティが追加されたものがあって、DCNDLという。この際ダブリンコアメタデータの内容は置いとくとして、国会図書館のがResource Description Framework(RDF)形式で公開されていて、これが参考になるでしょう。RDFXML内で記述することが出来るから、公開されているのは、RDF/XML形式ですね。またxml形式もある。
国立国会図書館ダブリンコアメタデータ記述(DC-NDL)実例集 | 国立国会図書館-National Diet Library
下の方に「2.資料の種類との記述例」というのがあるのでそこ見てください。xml形式のほうが楽そう。

総括

いろいろ調べたがJIS C 0451系とZ 8245-1系を写すだけみたいになってしまった。
メタデータの実際の作成を行ってみて、システムを考えていきたい。

空調負荷計算・エネルギーシュミレーターの件

いかがですか。わたしはいかがです。さて間が空きました。





私はなんかpython関係やら建築関係やらいろいろしておりましたが、まとめると以下の様になる。

  • RDBへのオブジェクトマッパ(SQLAlchemy)
  • 3D画像処理等(OpenGLOpenCV)
  • 機械設備・電気設備の営繕仕様書とか集める
  • DXF・DWG・JWCなどCADを調べる
  • 回路網計算を調べる

空調負荷計算・エネルギーシュミレーターについての適当な所感を書いてリンク貼っときます。

概算法

平米何Wとか言ってざっくりやるやつ。根拠資料としては営繕の建築設備計画基準となる。テクノ菱和のハンドブックにも書いてる。
Amazon CAPTCHA

最大熱負荷計算

営繕の建築設備設計に載ってる計算法で、これも根拠資料としては営繕の建築設備設計基準です。
https://www.amazon.co.jp/建築設備設計基準-平成27年版-公共建築協会/dp/4908525005/
空調衛生工学会出版の設計用最大熱負荷計算法という書籍がよくまとまっている。(絶版ですけど)
https://www.amazon.co.jp/dp/4874180108
今手元にないのであれなんですが、概要としては実効温度差(ETD)による近似をした標準外気温を用いる。夏季は4つの時間帯の実効温度差、冬季は1つの温度差による計算、だったと思う。またなんか微妙に公開されている実効温度差の地点数が少ないので、関西だったら京都でも兵庫でも全部大阪のETDみたいな計算をしていてほんとうに正しいのかよ、という気持ちになる。

エクセルで適当に書式作ってやれよ程度のもの。それでも多くの物件に関してはこれで十分でしょう。様式がA4で収まるのでよい。

ところでテクノ菱和のハンドブック、第2版と第4版持ってるんですが、第4版だいぶ情報量減った感じする。例えば風のあたり具合による空気の熱伝達率の変化のグラフとかが消えた。SI単位系になったのはいいことですが。

HASPEE

試して学ぶ熱負荷HASPEE ~新最大熱負荷計算法~ サポートページ
最大熱負荷計算のちょっとリッチになったバージョン。エクセルファイルで配布中。
設計用外気温度として設計用拡張アメダスデータ5種(夏季h-t,Jc-t,Js-t、冬季t-x,t-Jh)が国内842地点分収録などとてもうれしい。また壁とかガラスとかのデータ、人体負荷のデータとかもついてる。csv形式だし。計算も24時間x5種を行う。蓄熱負荷等に関しても一応はある。様式がやや気に入らないというのが難点。

HASP/ACLD/ACSS系

参考:
HASP(動的熱負荷計算・空調システム計算プログラム)ダウンロード
http://news-sv.aij.or.jp/kankyo/s13/OLDHP/inooka.pdf
https://www.chuden.co.jp/resource/corporate/news_112_N11229.pdf
国産シュミレーターで最近NewHASPが無償公開されている。歴史は古く、FORTRAN製。正直ソース見ても全く追い切れない。
hogehogeして気象データを年間1時間毎に突っ込むと、三角波近似で熱負荷応答を解いてくれる。現在室温と設定室温を一緒にしない。例えば設定温度から多少外れても許容されうる室内温度なら過負荷ではない、という感じになる。入力の様式はカード式の時の名残があり、クソそのものです。HASP/ACLDにより、熱負荷を計算し、ACSSを連成して機器運転状態と消費エネルギー・間欠負荷等まで計算できる。
これの入力はマジで職人芸だろ、という感じしかしない。出来ないことはないが、厳しい。

HVACSIM+(J)

http://www7a.biglobe.ne.jp/~nob_naka/jc.htm
名大中原研などに輸入・開発されたという。コミュニティがクローズっていうか、現状ウェブページもメンテナンスされてないようだし、一応申込を行えば郵送されるらしいが、私はしてません……。今ほんとにあるのかなって思う。

EESLISM

EESLISM - Udagawa Lab
工学院大学宇田川研製のソルバ。これには同富樫研のGUIフロントエンドがある。
http://www.hvacsimulator.net/
あと富樫准教授の博士論文とかが見れる。
DSpace at Waseda University: 建築設備シミュレーションソフトウェアの継続的開発法に関する研究
機器モデリングや各室連成計算等ができる。重要なのはC++及びC#開発だ、ということです。つまりOOP
あと富樫准教授の博論は多分配布のEESLISMには実装されて無いんだとは思うが、空調シュミレーターのソフトウェア開発としては参考になるところが多い。

MICRO-PEAK

MICRO-PEAK/2010 | 建築設備技術者協会-JABMEE-
これは使ったこと無いしあんまり内容も調べてないのでよくわからないが、なんとなく「15分単位での熱負荷シュミレーションが可能」「機器モデリングとかは無し」という感じに見える。5種類の外気温度データを収録とのこと。HASPEEもそうだったしBESTもそうなんですが、この拡張アメダス気象データがこれからテンプレになりそうかな、という気持ちです。

BEST

The BEST Program 【ザ・ベスト・プログラム】 建築物総合エネルギーシミュレーションツール
省エネ計画書|The BEST Program 【ザ・ベスト・プログラム】
多分日本で最も高品質な建築物消費エネルギーシュミレーターと思われる。とてもじゃないがサンデープログラマには手が出ないですね。
JAVA製で、アジャイルソフトウェア開発。データは現状のところXMLJPAを利用したパースをしているとのこと。
解説書理論編がとても詳しいので一読されたし。空調システムの連成計算は線形もしくは非線形多元連立方程式を解くか、常微分方程式を解くかを要求される時間間隔により最適方法を選ぶ形になっている。機器モデリングがちょっと特徴的で、参考書に説明がある。ファン・ポンプ類などは物理モデル(P=(n/n0)^3とか)の他の文献でもよく見る感じのモデリングをしているのですが、熱源機とかが例えばメーカーの技術資料に載っている付表をそのまま使うようになっていて、これを統計モデルと呼んでいる。実際これを野良で組もうと思うと辛さがある。(それでOpenCVをやりましょうねという動機となる)

欲望

Pythonねーのかよ!的なもの。Pythonの建築系ライブラリ、調べた限りで殆ど無い。(BACnetとかのライブラリはある)どういうことだ。あると思ったのになーというのが感想です。まあ実際パフォーマンス上良くないのだろうという気持ちしか無い。出来んことはなさそう。

pythonのdecorater,getattr,classmethodとかその辺

はじめに

pythonの関数などの振る舞いを調べました。何回調べても忘れているので、記事にします。
環境はpython2.7.11です。

pythonの関数(def文)

pythonの関数は変数を探すとき以下の方法で進む。

  1. 関数内部のローカルスコープで定義されてないか探す
  2. 関数内部のローカルスコープで見つからんかったら、スコープを大きくする。
  3. 最終的にglobalまで調べて見つからんかったらNameErrorを吐きます。

実際以下のようになる。

>>>def testscope():
>>>    print g
>>>#testscope() -> NameError
>>>g=1
>>>testscope() #-> 1
>>>del g
>>>#testscope() -> NameError

グローバルでgが定義されている時にtestscope.func_globalのgのキーをdelするとグローバルでもNameErrorとなる。

>>>testscope.func_global #->{ ...... ,"g":1 }とかいう感じの辞書
>>>del testscope.func_global["g"]
>>>#g -> NameError
>>>locals() == testscope.func_global #-> True

.func_globalって単にグローバルを参照してるだけなんだなという気持ち。

pythonの関数オブジェクトの扱い

上の、「関数内部のローカルスコープで見つからんかったら、スコープを大きくする。」というのは、結構面倒くさい感じだ。
ここで関数を返す関数などをつくる。

>>>g=1
>>>def testcloserscope():
>>>    g=2
>>>    def inner():
>>>        return g
>>>    return inner
>>>tcs=testcloserscope()
>>>tcs() #->2

スコープ階層としては、
グローバルのスコープ->testcloserscopeのスコープ->innerのスコープ となる。tcsを呼ぶとinnerのスコープをまず探し、innerのスコープでgが見つからんのでtestcloserscopeのスコープを探す。gが見つかったので2を返す。innerスコープではgはローカル変数じゃないが、testcloserscopeではgがローカル変数なので、innerから見た時、グローバルのgは遮蔽されている。またinner生成時に見つかったtestcloserscopeのスコープのgは保存されているので、tcs()->2となる。というふうに理解している。保存されているというか、

>>>tcs.func_closure #-> (<cell at 0x000... :int object at 0x000...>,)
>>>dir(tcs.func_closure[0]) #->[... ,"cell_contents"]
>>>tcs.func_closure[0].cell_contents #->2

などとなっている。以下を参考としました。
pythonのクロージャ - kk6のメモ帳*

@decoratorの件

ついでに糖衣構文であるところの@decoratorみたいなものを書くと、

>>>def testdeco(func):
>>>    def wrapper(*args, **kwargs):
>>>        print "decorated:"+func.__name__
>>>        func(*args,**kwargs)
>>>    return wrapper
>>>@testdeco
>>>def testfunc():
>>>    print "hoge"
>>>testfunc()
>>>#->"decorated:testfunc"
>>>#->"hoge"
>>>testfunc.__name__ #->"wrapper"

という感じだが、これは以下と等価。

>>>def testdeco(func):
>>>    def wrapper(*args, **kwargs):
>>>        print "decorated:"+func.__name__
>>>        func(*args,**kwargs)
>>>    return wrapper
>>>def testfunc():
>>>    print "hoge"
>>>testfunc=testdeco(testfunc) #この辺を@testdeco defなどと書ける。
>>>testfunc()
>>>#->"decorated:testfunc"
>>>#->"hoge"
>>>testfunc.__name__ #->"wrapper"
>>>testfunc.func_closer #->(<cell at 0x00... :function object at 0x00... >,)

デコレート後のtestfuncに入っている実体としてはwrapperで、wrapperのローカル変数にはfuncはないけど、wrapperのクロージャに元のtestfuncが入っているのでhogeできるよ~。ということですね。

関数をクラスにぶち込むぞ!!!!という気概

クロージャはイミュータブル

上のような気概ですが、その前にクロージャがイミュータブルであることを確認します。

>>>def testcloserscope():
>>>    g=[]
>>>    def inner():
>>>        return g
>>>    return inner
>>>tcs=testcloserscope()
>>>g2=tcs() #->[]
>>>g2.append(1) #g2=[1]
>>>tcs2=testcloserscope()
>>>tcs2() #->[]

gをミュータブルな型にした。もしtcs()がtestcloserscope内のgのポインタ(的なもの)を返していれば、ポインタを操作すればtestcloserscope内のgを変更できることになる。
しかし、あくまでtcsでの保存されたスコープはクロージャであって、スコープの外側から中のgを変更することは出来なかった。(少なくともこの例では)

クラスの仕様とかのよくわからん感じを感じてもらいたい。

さて以下の様なクラスのメソッドがあります。

class A(object):
    x=1
    def hoge(self):
        return self.x

これを普通のクラスの普通のメソッドだと思っているし、実際以下のようになる。

>>> A.x #->1
>>> A.hoge #-> <unbound method A.hoge>
>>> #A.hoge() #-> unbound method hoge() must be called with A instance as first argument
>>> a=A()
>>> a.hoge #-> <bound method A.hoge of <__main__.A object at 0x00...>>
>>> a.hoge() #-> 1
>>> a.x=2
>>> a.hoge() #-> 2
>>> A.x #->1
>>> A.x=3
>>> a.x #->2
>>> a2=A()
>>> a2.hoge #->3

期待通りですね?ではこれはどうか。

class B(object):
    x=[]
    def hoge(self):
        return self.x

クラスのattributeをミュータブルな型にした。こうなる。

>>> B.x #->[]
>>> B.hoge #-> <unbound method B.hoge>
>>> #B.hoge() #-> unbound method hoge() must be called with B instance as first argument
>>> b=B()
>>> b.hoge #-> <bound method b.hoge of <__main__.B object at 0x00...>>
>>> b.hoge() #-> []
>>> b.x.append(1)
>>> b.hoge() #-> [1]
>>> B.x #->[1] !!!!
>>> B.x.append(2)
>>> b2=B()
>>> b2.hoge #->[1,2]

Bのクラス内で宣言したものがリストなどのミュータブルなものである場合、普通にインスタンスに参照が渡されているっぽく見える。
b.x=B.xめいた処理がどこかで行われている。

とりあえずメソッドの束縛とか非束縛とかについて考える。

クラス内のメソッドについては以下のように調べる。

>>> A.hoge is a.hoge #->False
>>> A.hoge.im_class #->__main__.A
>>> A.hoge.im_self #->None
>>> A.hoge.im_func #-> <function __main__.hoge>
>>> a.hoge.im_class #->__main__.A
>>> a.hoge.im_self #-> <__main__A at 0x3eab898>
>>> a.hoge.im_self is a #->True
>>> a.hoge.im_func #-> <function __main__.hoge>
>>> a.hoge.im_func is A.hoge.im_func #->True
>>> #上記はBも同様

>>> A.hoge.im_func(A) #->3
>>> A.hoge.im_func(a) #->2
>>> a.hoge.im_func(A) #->3
>>> a.hoge.im_func(a) #->2

>>> B.hoge.im_func(B) #->[1,2]
>>> B.hoge.im_func(b) #->[1,2]
>>> b.hoge.im_func(B) #->[1,2]
>>> b.hoge.im_func(b) #->[1,2]

>>> B.hoge.im_func(A) #->3

面倒なので名前で察してほしい。以下のことがわかる。

  1. A.hogeとa.hogeは異なったインスタンスである。
  2. A.hoge.im_selfはNoneであって、束縛されていない。
  3. a.hoge.im_selfはa自身で、束縛されている。
  4. A.hoge.im_func,a.hoge.im_funcは元の関数らしいので、return A.xだかreturn a.xだかとなる。
  5. .im_func(B)はなんか同じものが参照されている。
  6. .im_funcは同じような関数だったので別にB.hoge.im_func(A)としても通る。
デスクリプタのあれ

3. データモデル — Python 2.7.x ドキュメント
公式を読むとこう書いてある。

属性アクセスのデフォルトの動作は、オブジェクトの辞書から値を取り出したり、値を設定したり、削除したりするというものです。例えば、 a.x による属性の検索では、まず a.__dict__['x'] 、次に type(a).__dict__['x'] 、そして type(a) の基底クラスでメタクラスでないものに続く、といった具合に連鎖が起こります。

オーケー、調べよう。

>>>a.__dict__ #->{"x":2}
>>>a2.__dict__ #->{}
>>>A.__dict__ #->{...... ,"hoge":<function __main__.hoge>,"x":3}
>>>b.__dict__ #->{}
>>>b2.__dict__ #->{}
>>>B.__dict__ #->{...... ,"hoge":<function __main__.hoge>,"x":[1,2]}

わかりましたね?a,a2のhoge,bやb2のhogeやxは結局AやBのhogeを呼び出しているのだ。等価っぽいコードを書くと以下のようになる。

def search(ins,attrkey):
    if attrkey in ins.__dict__.keys():
        return ins.__dict__[attrkey]
    else:
        if attrkey in type(ins).__dict__.keys():
               return type(ins).__dict__[attrkey]
        else:
            ...

組み込み関数のgetattrはほぼ上のsearchのような関数であるようだ。ただし、メソッド呼び出しの場合は引数が定義時そのままの関数が呼び出されるのではなく、ラップされてboundとかunboundなメソッドが帰るようになっている。

メソッドの動的結合

関数オブジェクト以外についてはクラスオブジェクト・インスタンスオブジェクトの両方の属性に代入できる。
クラスオブジェクトに代入した場合、上述の通りインスタンスオブジェクトからも__dict__を遡って呼び出すことが出来る。
関数オブジェクトは、インスタンスの属性として代入した場合、バインドされない。
以下のようになる。

>>>def fuga(self):
>>>    return self.x**5
>>>fuga(a) #->32
>>>a.fuga=fuga
>>>#a.fuga() ->Type Error:fuga() takes exactly 1 argument(0 given)

しかしクラスに代入した場合、ラップされたメソッドになり、クラス定義時に定義した関数と同じ扱いになる。この時点ではバインドはされていない。
また、インスタンスオブジェクトから遡って呼び出せる。この場合の呼び出しはバインドされる。

>>>A.fuga=fuga
>>>a.fuga() #-> 32
>>>#A.fuga() -> unbound method

インスタンスバインドされているメソッドは呼び出すとき暗黙的に第一引数に自らを渡すことになる。関数定義時にはselfと書かれる。
バインドメソッドのように暗黙的に第一引数にcls(Aなど)を取ることにする関数を作れる。クラスメソッドという。これは関数をclassmethod()でラップしなければならない。デコレータで@classmethodと書いてもよい。

>>>@classmethod
>>>def foo(cls):
>>>    return -cls.x
>>>A.foo=foo
>>>A.foo() #->-3 
>>>a.fuga() ->-2
疲れてきた

バインドされたりされなかったりするの、なんかクラスオブジェクトに特異的な感じする。多分typeのsetattrかなんかがいろいろしているんだろうな。

pandasをwhlで入れる

pythonのデータ保存の考え

pythonでデータを保存するには多分以下の方法のどれかを使うのが手っ取り早かろう。

  1. 関係データベースシステムRDBMSを問い合わせ言語APIのsqlite3で操作する
  2. 標準ライブラリのpickleを使ってdumps,loadする
  3. xml.etree.ElementTreeを使ってXML形式で保存読込する
  4. jsonを使ってJSON形式で保存読込する。
  5. xlrdなどでEXCEL形式で保存読込する。
  6. pandas等でcsv形式で保存読込する。
  7. なにか自分で入出力クラスを実装して保存読込する。

仕様によって向き不向きがあるので検討する

手っ取り早くやるときはまあなんでもいいと思うけど、データを保存するのだから、それをのちのち使うのだろう、と考えるのが自然だと思う。
この時は何を考慮する必要があるのか。

  • データの正規性

データが正規化されていると型処理が非常に楽。というかそのままsqlでぶち込めるし読める。何も考える必要が無い。
データが非正規的だと面倒さが加速する。

  • データの構造

木は極めて面倒。データだか実装だか全然わからん。いやわからんことはないが、実装がデータに依存してくるから、データを拡張すると実装が爆発的に加速。
カオスなコードになる。

  • データの拡張性

逆にxml等の半構造データベースは拡張が容易。例えばこのレコードだけ特殊なkeyを設けるとかできる。まあテーブルを分割しろよ、正規化していけ、と思わなくもないが、その結果隣接テーブルを作るはめになって死、が容易に想像できる。

  • データの一意性とか完全性とか

関係データベースは正規性を保っておけば一意性・完全性に関してかなり優位だし、どの本よんでもそう書いてある。
半構造データベースはその辺がほぼ無理。

  • データの検索性

csvとかjsonとか検索性あるのってレベル。必然的にpandasとか補助的なライブラリを使うこととなる。

  • 可読性・可視化性

excleとかで見れると非常に楽。csv,jsonテキストエディタで見れるしかなり楽。一方RDBは専用のツールが必要。pickleとか言うまでもない。

  • エンジンの入手性

簡単に操作環境を構築し直せる方が良い。標準ライブラリに入ってるものは簡単に環境を構築できる。
pickleは保存できるクラスがモジュールトップレベルじゃないとダメ~という縛りがあるから思ったよりその辺が面倒になる。

  • 書きやすさ

コードの生産性があるので、単に使い慣れてるもの使えばよいのでは、というのが基本。しかしそうであればオレオレ実装が一番楽となるが、オレが明日も同じ気持かというとそうではないのだ……
sqlクエリを書くのは、文字列操作じみた方法になってくるのでこれはこれでキモいところがある。

まとめるとこう。

実装 正規性 構造 拡張性 完全性 検索性 可読性 入手性 書きやすさ
sqlite3 × ×
pickle × × × ×
ElementTree ×
json × ×
excel × × ×
csv ×
人力 × × × ×

多分こんな感じ。気持ちをまとめるとこころにやさしい。

pandasを入れてなかった

のでwhlで入れます。
いつもどおりhttp://www.lfd.uci.edu/~gohlke/pythonlibs/からpy2.7-win64.whlを取ってきてpip install pandas~.whlでインストールする。

cygwin win64bit版を入れたり、bash+mintty+console環境を設定したりする

環境的な話

現状、こういうものを使いたいという感情がある。

  1. windows7 64bit
  2. gcc
  3. bash+mintty
  4. エディタ
  5. ipython(win64版、導入済み)
  6. sqlite3
cygwin 64bitの導入

Cygwin(64bit)とgitのインストール - Qiita
Cygwinのインストールとapt-cygのインストール - Qiita
このあたりに従って入れる。

環境変数の設定は.bash_profileを触ってもできるそうですけど、今回はwindowsシステムの方に書きました。
参考これ。
Cygwinインストール後のWindows環境変数設定 - Qiita

windowspythonが入っている場合はcygwinpythonと干渉するのでpathの書き方に注意で、以下のようにする。
Windows版とcygwin版の共存でハマる - nelnal@python - pythonグループ
ポイントとしては2点で、
pathのpython(win版)の位置をc:\cygwin/bin~~より前に書くこと。
pythonpathを設定すること
でした。

bash+mintty+ipythonの対話モードをできるようにする。

ここまでで以下の状態になる。
bash+minttyは動く。mintty上でipythonは動かない。cmd.exe上ではipythonが従来通り動く。
原因はminttyのパイプ処理がどうのこうのというあたりらしい。
MinGW の mintty で対話モード、ついでに vim 設定 | ユニマージュ
結論だけ書けば、winpty(のconsole.exe)でwindowsアプリをラップすれば良い。

winptyの導入はビルドが必要。

rprichard/winpty · GitHub
ここのzipをダウンロードしてきて、cd /hogehoge/winpty-masterして、./configureしてmakeすればよい。
なんかgccが見つからんとかなんとか言われた気がするがあんまり覚えてない。
.bashrcに

alias gcc='x86_64-w64-mingw32-gcc.exe'
alias g++='x86_64-w64-mingw32-g++.exe'

みたいなことを書いた。
最終的にwinpty-master/buildにconsole.exe、winpty.dll、winpty-agent.exeができるので、この三つを適当なところにおいて(今回は~/buildにまとめて入れた)

alias 'python'='~/build/console.exe python'
alias 'ipython'='~/build/console.exe ipython'

とする。これでipythonがmintty上で動く。

Windows7 64bitでPython2.7+numpy+matplotlib+ipythonを入れる

Windows7 64bitを入れなおした

Linuxで開発するほうが楽なんじゃねーのと思い始め、最近になってようやく仮想化マシンを導入することに決めた。
で、VirtualBox+Ubuntu14.04(32bit)を入れてみたら環境的には楽になってるのだが、重くてしんどい。
ホストメモリ4GBで半分の2GBをゲストに割り当てても厳しいものは厳しい。
それでメモリ増設しようという流れになったが、Windows7 32bitではメモリが4GBまでしか認識しない。
仮想化マシンを導入したことでメイン機が32bitである必要もなくなったため
めんどうながらWindows7 64bitを入れなおした。

IPython導入覚書

前回のPCがWindows7 64bitでこのときよくわかってなかったのでIPythonを入れられなかった。
3年ぶりにリベンジした。

手順はこう。

  1. Python2.7 64bitを入れる
  2. pipを使用可能にする
  3. whlでnumpyその他をインストールする
Pythonを入れる

公式Python Releases for Windows | Python.orgに飛ぶ。
Windows x86-64 MSI installerとかをダウンロードしてインストーラを実行する。

パス通す。環境設定のPathに

;C:\Python27;C:\Python27\Lib\site-packages;C:\Python27\Scripts

を付け足す。

get-pip.pyする

Python - いつの間にかpipのインストールが楽になってた件 - Qiita参照。

まずtempディレクトリを作ってコマンドプロンプトで移動しておく。
今回はC:\work\150426などとしました。

次にget-pip.pyをとってきて実行する。
Installation — pip 6.1.1 documentationのget-pip.pyをダウンロードしてきてtempディレクトリにget-pip.pyとして保存。
実行する。

python get-pip.py

これでpipまで入りました。pipの実行ファイルはC:\Python27\Scriptsに入っている。

whlでnumpyその他をインストールする

Gohlkeさんの非公式バイナリwhlをさっきインストールしたpipを使ってインストールします。
なんかインストーラー版が昔あったような気がしましたが、今回見つけられなかった。
ローカルのwhlからのインストールを覚えとけばたぶんvirtualenv環境でも何とかなるだろうという考えでした。

Python Extension Packages for Windows - Christoph Gohlkeへ行き、必要なパッケージをダウンロードする。
環境としてはpy2.7 win-amd64となるので、そんな感じのやつをダウンロードする必要がある。
noneとかanyとか書いてるやつは環境を指定していないという意なので気にせずダウンロード。
今回は以下のパッケージをダウンロードする。ダウンロードしたやつはtempディレクトリにコピーするなり移動するなりする。

  • numpy 1.9.2
  • Pillow 2.8.1
  • scipy 0.15.1
  • python_dateutil 2.4.2
  • pytz 2015.2
  • pyparsing 2.0.3
  • six 1.9.0
  • setuptools 15.1
  • matplotlib 1.4.3
  • pyzmq 14.6.0
  • certifi 14.5.14
  • backports.ssl_match_hostname 3.4.0.2
  • tornado 4.1
  • pyreadline 2.0 #
  • pygments 2.0.2
  • markupsafe 0.23
  • jinja2 1.2
  • mistune 0.5.1
  • rpy2 2.5.6
  • pycairo 1.10.0
  • pyqt4 4.11.3
  • ipython 3.1.0
  • vertualenv 12.1.1

先ほどのtempディレクトリに移動して、

pip install numpy-1.9.2+mkl-cp27-none-win_amd64.whl

などとしてやればok。これでパッケージがインストールされる。
現在インストールされているパッケージは

pip freeze

で確認できる。
パッケージをアンインストールしたい場合は

pip uninstall パッケージ名

でアンインストールできる。
パッケージ間には依存関係があるので注意する。
具体的には以下のように依存している。たとえばmatplotlibを入れるためにはsixとかpytzとかが必要。

  • matplotlib:numpy, dateutil, pytz, pyparsing, six, setuptools
  • ipython:setuptools, pyzmq, tornado, pyreadline, pygments, markupsafe, jinja2, mistune, rpy2, pycairo, matplotlib, pyqt4 or pyside,
  • tornado:certifi and backports.ssl_match_hostname.

今回はほかのパッケージに依存していないものを先にインストールしていったが、実際いきなりipythonをインストールしても、whlファイルがtempディレクトリにあるならpipが認識してそこからインストールしてくれるかもしれない。

virtualenv覚書

ついでにvirtualenvを入れたので使い方を忘れぬうちに書く。

virtualenv env1

とするとカレントディレクトリにenv1ディレクトリができる。
仮想環境モードにするには

Scripts\activate.bat

を実行。ここでpip install なんとかしていけばよい。
仮想環境を終了するときは

Scripts\deactivate.bat

とする。

気になること

現在virtualenv仮想環境にてpipを使うとurllib3がInsecurePlatformWarningを吐く。よくわからんけどとりあえずsixぐらいだったらインストールできたのでまたなんか引っかかったら考えよう。

ET.Elementを書き出せるDictっぽいものを作る

ポイント
  • プログラム上ではdict型(らしきもの)でいろいろ動かせるようにする
  • 保存するときにElement型にしてtree.write()で出力する
  • 読出するときはET.parse()で読んでdict型(らしきもの)に入れる。
  • Dictでは動的型付けのまましたい。
  • ただし変換した時にtagにあたるものや、ファイル内での唯一keyとなるnameとかはstrかunicodeとする。
  • Elementに変換するときに型チェックを行いたい。intとかfloatはプログラム上での型情報を付加した上でstrに変換する。
  • 読み出し時にDictを復元する。intとかは元通りに戻す。
  • 保存・読出時にめんどくさそうなのでDictを要素に持つDictとかは作らない。再帰して終わらなさそう。
  • とはいえ最低Dictには前者・後者が欲しい。プログラム上ではイテレータっぽい動きをしたい。
  • とすれば、Dictはリストに前者・後者のポインタを持っときたい。
  • 唯一keyがわかっていればポインタを再構成できる。
  • fileハンドルを作ろう。そうすればファイルネームとかヘッダとかの管理もさせられる。
実際にやってみた
#EDsys.py
#coding:utf-8

import xml.etree.ElementTree as ET
from is_ETwritable import is_ETwritable
from is_numeric import is_numeric
class FileHandle(object):
  def __init__(self,filename):
    self.dict={}
    self.dict["filename"]=filename
    self.Items={}
  def __getitem__(self,key):
    return self.dict[key]
  def __setitem__(self,key,value):
    if is_ETwritable(key):
      self.dict[key]=value
    else:
      raise
  def setItem(self,item):
    if type(item)==Item:
      self.Items[item["name"]]=item
    else:
      raise
  def getItem(self,key):
    return self.Items[key]
  def write(self):
    a=ET.Element(self["filename"])
    td=dict(self.dict)
    del td["filename"]
    for i in td:
      aa=ET.Element(i)
      if is_ETwritable(td[i]):
        aa.text=td[i]
      elif is_numeric(td[i]):
        aa.text=str(td[i])
        aa.attrib["progtype"]=str(type(td[i]))
      else:
        raise
      a.append(aa)
    for i in self.Items:
      a.append(self.getItem(i).toElement())
    t=ET.ElementTree(a)
    print self["filename"]
    t.write(self["filename"],"utf-8")

class Item(object):
  def __init__(self,Itemtype,name):
    if is_ETwritable(Itemtype) and is_ETwritable(name):
      self.dict={}
      self.dict["Itemtype"]=Itemtype
      self.dict["name"]=name
      self.before=[]
      self.next=[]
    else:
      raise
  def __getitem__(self,key):
    return self.dict[key]
  def __setitem__(self,key,value):
    if is_ETwritable(key):
      self.dict[key]=value
    else:
      raise
  def setnext(self,node):
    if type(node)==Item:
      self.next.append(node)
      node.before.append(self)
    else:
      raise
  def setbefore(self,node):
    if type(node)==Item:
      self.before.append(node)
      node.next.append(self)
    else:
      raise
  """def dictprint(self):
    print self.dict.__repr__()
  def fullprint(self):
    self.dictprint()
    print "before"
    for i in self.before:
      i.dictprint()
    print "next"
    for i in self.next:
      i.dictprint()"""
  def toElement(self):
    a=ET.Element("Item")
    #print self.dict
    td=dict(self.dict)
    #print td
    for i in td:
      aa=ET.Element(i)
      #print i
      if is_ETwritable(td[i]):
        aa.text=td[i]
      elif is_numeric(td[i]):
        aa.text=str(td[i])
        aa.attrib["progtype"]=str(type(td[i]))
      else:
        raise
      a.append(aa)
    for i in self.before:
      aa=ET.Element("before")
      aa.attrib["name"]=i["name"]
      a.append(aa)
    for i in self.next:
      aa=ET.Element("next")
      aa.attrib["name"]=i["name"]
      a.append(aa)
    return a

def parse(filename):
  EL=ET.parse(filename).getroot()
  fh=FileHandle(filename)
  for i in EL.getchildren():
    if i.tag =="Item":
      itemtype=None
      name=None
      somedict={}
      for j in i.getchildren():
        if j.tag=="Itemtype":
          itemtype=j.text
        elif j.tag=="name":
          name=j.text
        elif j.tag=="next" or j.tag=="before":
          continue
        else:
          if "progtype" in j.attrib:
            somedict[j.tag]=typedecode(j.attrib["progtype"],j.text)
        
      assert not itemtype==None
      assert not name==None
      a=Item(itemtype,name)
      for i in somedict:
        a[i]=somedict[i]
      fh.setItem(a)
    else:
      fh[i.tag]=i.text
  for i in EL.findall("Item"):
    x=fh.getItem(i.find("name").text)
    for j in i.findall("before"):
      x.before.append(fh.getItem(j.attrib["name"]))
    for j in i.findall("next"):
      x.next.append(fh.getItem(j.attrib["name"]))
  return fh,EL

def typedecode(str,value):
  if str=="<type 'int'>":
    return int(value)
  if str=="<type 'float'>":
    return float(value)  

あとis_ETwritable.pyに関しては

#coding:utf-8

def is_ETwritable(string):
  if type(string)==str or type(str)==unicode:
    return True
  else:
    return False
おもむろに

これからこれつかいます。

xml.etree.ElementTree.ElementTree.write()に関して

xml.etree.ElementTree

pythonxmlを扱うにあたって、python標準ライブラリにxmlモジュールがあるのでそれを使う。xmlモジュールには大きくはxml.domとxml.saxとxml.etreeというのがありますが、etree.ElementTreeがいろいろ参考になるところが多いので、それを使う。W3C標準だとDOMを使うべきなのかな、って気もするけど、まあローカルで使うだけなのでElementTreeでいいでしょう。

参考としては、だいたいこの辺。
19.13. xml.etree.ElementTree — ElementTree XML API — Python 2.7ja1 documentation
PythonでElementTreeを使ってXMLを処理する方法 - hikm's blog

ElementTreeの使い方

だいたい以下のようになる。

#coding:utf-8

import xml.etree.ElementTree as ET

filename="sample.xml"

#読み込むとき
#tree=ET.parse(filename)
#root=tree.getroot()
#root.tag="hoge"

#新規で作るとき
root=ET.Element("hoge")

#タグを変える
root.tag="fuga"

#テキストを入れる
root.text=u"こんにちは"

#attribute要素を入れる
root.attrib["zokusei"]="foo"
#よくよく読むとあんまり良くない構文らしい
#root.set("zokusei","foo")とかのが良いという。

#子のElementを入れる
root.append(ET.Element("bar"))
#複数突っ込むときはroot.extend(<i>ElementsList</i>)

#子の中からタグ名で探す
root.find("bar")

#一回ElementTreeにして、書き出す。

tree=ET.ElementTree(root)
tree.write(filename,"utf-8")
実行結果

sample.xmlが出力されて、中身はこんなかんじになる。

<?xml version="1.0"?>
<fuga zokusei="foo">
test
<bar/>
</fuga>
メリットとデメリット

xml.etree.ElementTree超簡単やん!これ使えばええやん!読み出しはET.parse、書き出しはtree.write()したらええんや!というのがうれしい。だいたいそれぐらいの能力で満足できそう。ただし、write()にはしばしば怒られうる。と言うのは例えば上のコードにおいて

#tag,text,attribにintリテラルとかfloatリテラルを突っ込んでもエラーにならない。
root=ET.Element(1)
root.tag=1.1
root.text=1
root.set(1.1,5)
#しかしそういうElementを含むtreeをwriteするとerror
tree=ET.ElementTree(root)
tree.write(filename,"utf-8") #できない

微妙に腹立ちます。

文字コード形式をutf-8の設定にした場合の話ですけど、
tree.write()はstr型とunicode型はそのまま書けるし、parse()でそのまま読むらしい。
けど少なくともintとかfloatは書けない。numpy.int16とかそのへんも試してないけどきっと書けないだろうな。

付き合い方を考える

xmlは基本的にはDBの書式だと思うし、一回のスクリプトで一つのxmlファイルに何度もアクセスして何度も書き換えて、ってものではないだろう。一回ロードして、プログラム上でグリグリ変更して、最終的にセーブします、ってなもんでしょう。
で、その上で書き込み時になにかこう、それっぽいクラスからElementクラスへ渡すことになるのだから、そこでそのへんのチェックなり何なりすればよろしかろう、と思います。

電気設備の計算をpythonでやる(2)-動力用変圧器容量の算定

動力用変圧器容量の算定

だいたい第一回電気設備の計算をpythonでやる(1)-電灯コンセント用変圧器容量の算定 - suzukiyou blogと流れが一緒です。

  1. 負荷を突っ込んで、出力kWから入力を換算して入力kVAを出す。
  2. 動力のタイプから需要率DFを出す。
  3. 入力と需要率から最大需要電力kVAを出す。
  4. 負荷を遮断器に突っ込んでいく。(動力盤に入ってる遮断器をイメージする)
  5. 更に遮断器を遮断器に突っ込んでいく。(動力盤の主遮断器とかのイメージ)
  6. トランス直近に遮断器があることにして、全部の負荷を突っ込む。
  7. 仮想的なトランス直近遮断器と将来需要電力を入れて、トランスを選定する。

前回との違いは、盤らしき変数を作らずに全部遮断器でやる、ということと、仮想的なトランス直近遮断器を作った事となります。
前者は「盤とかクラス増えてややしこいし、結局盤にも主遮断機あるんやろ」という考えによります。
後者に関してですが、実際の施工においてだいたいはトランス直近のキュービクル内に遮断器があって、そっから各盤まで配線を伸ばしているというふうになるのでこんな遮断器は普通存在しないなぁと思いながら作りました。しかし各負荷を足して最大需要電力を出すのを今後遮断器においてもやっていくだろうこと、トランスと遮断器の療法で同じような作業をするのが気に喰わないことなどからそうしました。

プログラミング上の工夫

前回の反省:
ちゃんとコメント書かなアカンなと思ってかいた。
出力もちゃんとしないとわかんねーなと思って書くことにした。

その他:
Mydictはどうせ今後も書くのでimportすることとし、また今回から、数値型の判定を関数化しました。
Re:数値型判定はどうしたらいいのだろう? - 銀月の符号
これの2番を使わせてもらいました。

コード

#sample150125.py
#coding:utf-8

from Mydict import Mydict
from is_numeric import is_numeric

class PowerLoad(Mydict):
  pass

def createPowerLoad(ElectricLoadType,LoadkW,LoadType,LoadSeason,translateinput=None,DF=None):
  #ElectricLoadTypeは"電動機or電熱器orインバータor多極電動機",
  #"電動機"の場合はその相も含む。で、ElectricLoadTypeList中から選ぶ
  #ElectricLoadTypeDictよりkWをkVAに換算するための掛率TranselateLoadConstを選ぶ。
  #LoadkWは負荷(kW)
  ElectricLoadTypeDict={"motor1phi":1.33,\
  "motor3phi":1.25,\
  "motorhighVoltage":1.176,\
  "heater":1.0,\
  "inverter":1.4,\
  "machine":None}
  assert ElectricLoadType in ElectricLoadTypeDict.keys()
  assert is_numeric(LoadkW)

  #LoadTypeは需要率DF決定のための機器種類でその中から選ぶ、汚水ポンプとかエアコンとか
  #LoadTypeDictは機器種類とその需要率DF(%)
  LoadTypeDict={"Heater":100,\
  "LiftingPump":30,\
  "SanitaryPump":30,\
  "PoolPump":100,\
  "HotWaterBoiler":30,\
  "HotWaterPump":30,\
  "SepticTank":30,\
  "SepticBlower":100,\
  "SpringWaterPump":0,\
  "VentilateFan":100,\
  "Refrigerator":80,\
  "Chiller":80,\
  "PACFan":100,\
  "AHU":100,\
  "PAC":80,\
  "RoomAirCon":85,\
  "CoolWaterCirculationPump":100,\
  "CoolingTower":100,\
  "SupplyPump":10,\
  "ElectricPrecipitator":50,\
  "Boiler":0,\
  "HotWaterCirculationPump":0,\
  "FirePump":0,\
  "Exhauster":0,\
  "Shutter":0,\
  "Elevator":80,\
  "Lift":40,\
  "Escalator":90,\
  "MultistoryParkingLift":60,\
  "machine":None}
  """
  LoadTypeDict={"Heater":100,\ #電気温水器とか
          "LiftingPump":30,\ #揚水ポンプ
  "SanitaryPump":30,\ #汚水雑排水ポンプ
  "PoolPump":100,\ #プール濾過用ポンプ
  "HotWaterBoiler":30,\ #給湯ボイラー
  "HotWaterPump":30,\ #給湯ポンプ
  "SepticTank":30,\ #浄化槽
  "SepticBlower":100,\ #浄化槽ブロア
  "SpringWaterPump":0,\ #湧水ポンプ
  "VentilateFan":100,\ #換気ファン
  "Refrigerator":80,\ #冷凍機
  "Chiller":80,\ #冷温水発生機
  "PACFan":100,\ #パッケージファン
  "AHU":100,\ #エアハンドリングユニット
  "PAC":80,\ #設備用・業務用・ビル用マルチエアコン
  "RoomAirCon":85,\ #ルームエアコン
  "CoolWaterCirculationPump":100,\ #冷水・冷温水循環ポンプ
  "CoolingTower":100,\ #冷却塔
  "SupplyPump":10,\ #補給水ポンプ
  "ElectricPrecipitator":50,\ #電気集じん機
  "Boiler":0,\ #ボイラー(空調用)
  "HotWaterCirculationPump":0,\ #温水循環ポンプ
  "FirePump":0,\ #消火ポンプ
  "Exhauster":0,\ #排煙ファン
  "Shutter":0,\ #シャッター
  "Elevator":80,\ #エレベーター
  "Lift":40,\ #小荷物専用昇降機
  "Escalator"90,\ #エスカレーター
  "MultistoryParkingLift":60,\ #立体駐車場機械
  "machine":None}#工作機械
  """
  assert LoadType in LoadTypeDict.keys()
  
  #負荷使用期間LoadSeasonは次のLoadSeasonListから選ぶ。
  LoadSeasonList=["summer","winter","annual"]
  assert LoadSeason in LoadSeason
  
  #PowerLoadインスタンスを生成して、これに入力を突っ込んで返す。
  #PowerLoadはMCCBLoadに突っ込んでいくので、とりあえず最大需要電力MaxDemandkVAがわかればよろしい。
  #kW→kVA換算を無効にして直接kVAを突っ込んでくるように拡張する可能性があるかも知んない。
  a=PowerLoad()
  a["ElectricLoadType"]=ElectricLoadType
  a["LoadkW"]=LoadkW
  #練習問題見てたらあった。引数としてtranslateinputがある場合はそれを優先する。
  if translateinput==None:
    a["TranslateLoadConst"]=ElectricLoadTypeDict[ElectricLoadType]
    assert a["TranslateLoadConst"] != None
  elif is_numeric(translateinput):
    a["TranslateLoadConst"]=translateinput
  else:
    raise  
  a["TranselateVA"]=LoadkW*a["TranslateLoadConst"]
  
  a["LoadType"]=LoadType
  a["LoadSeason"]=LoadSeason
  #引数としてDFが突っ込まれた時はDFを優先する。工作機械とか標準DFがないものもある。
  if DF==None:
    a["DF"]=LoadTypeDict[LoadType]
    assert a["DF"] != None
  elif is_numeric(DF):
    a["DF"]=DF
  else:
    raise
  a["MaxDemandkVA"]=a["TranselateVA"]*a["DF"]/100.0
  
  return a


class MCCBLoad(Mydict):
  pass
  
def createMCCBLoad(LoadList):
  #MCCBLoadインスタンスを生成する。
  #MCCBが受け持つLoadListをつくる。あくまでPowerLoadであってMCCBLoadではない。
  a=MCCBLoad()
  a["LoadList"]=[]
  a["SummerDemandVA"]=0.0
  a["WinterDemandVA"]=0.0
  
  #LoadListは負荷のリスト,もしくは負荷単体
  #LoadListあるいは要素がPowerLoadクラス、MCCBLoadクラスであることを確認する。
  #それぞれの場合で負荷をPowerLoadに帰着してPowerLoadcalに突っ込んで最大需要電力VAを計算する。
  #summer,winter両方で計算して大きい方をMCCBの使用期間、最大需要電力とする。
  if type(LoadList)==PowerLoad:
    PL=LoadList
    a=PowerLoadcal(a,PL)
  elif type(LoadList)==MCCBLoad:
    ML=LoadList
    for i in ML["LoadList"]:
      a=PowerLoadcal(a,i)
  elif type(LoadList)==list:
    for i in LoadList:
      if type(i)==PowerLoad:
        a=PowerLoadcal(a,i)
      elif type(i)==MCCBLoad:
        ML=i
        for j in ML["LoadList"]:
          a=PowerLoadcal(a,j)
  else:
    raise
  return a

def PowerLoadcal(MCCB,Load):
  #負荷使用期間リスト
  LoadSeasonList=["summer","annual","winter"]
  a=MCCB
  l=Load
  a["LoadList"].append(l)

  if not l["LoadSeason"] in LoadSeasonList:
    raise
  if l["LoadSeason"] in LoadSeasonList[0:2]:
    a["SummerDemandVA"]+=l["MaxDemandkVA"]
  if l["LoadSeason"] in LoadSeasonList[1:3]:
    a["WinterDemandVA"]+=l["MaxDemandkVA"]
  if a["SummerDemandVA"]>a["WinterDemandVA"]:
    a["MaxDemandkVA"]=a["SummerDemandVA"]
    a["LoadSeason"]=LoadSeasonList[0]
  elif a["SummerDemandVA"]==a["WinterDemandVA"]:
    a["MaxDemandkVA"]=a["WinterDemandVA"]
    a["LoadSeason"]=LoadSeasonList[1]
  elif a["SummerDemandVA"]<a["WinterDemandVA"]:
    a["MaxDemandkVA"]=a["WinterDemandVA"]
    a["LoadSeason"]=LoadSeasonList[2]
  else:
    raise
  return a  

class Transe(Mydict):
  pass
  
def createTranse(MCCB,futureLoad=0.0):
  #今回はとりあえずトランス直近に主幹のMCCBがあることにして突っ込む。
  #TranseSize選定のためのリスト
  TranseSizeList=[30,50,75,100,150,200,300]
  
  #Transeインスタンスを作って直近MCCBと将来用需要電力を突っ込む。
  a=Transe()
  a["MaxDemandkVA"]=MCCB["MaxDemandkVA"]
  a["FutureDemandkVA"]=futureLoad
  a["MaxDemandkVA"]+=futureLoad
  
  #TranseSizeを選定する
  a["TranseSize"]=None  
  for i in TranseSizeList:
    if a["MaxDemandkVA"]<i:
      a["TranseSize"]=i
      break
  assert a["TranseSize"]!=None
  return a    
if __name__=="__main__":
  #負荷リスト、遮断機リストをつくる
  LoadList=[]
  MCCBList=[]
  #負荷を突っ込む
  LoadList.append(createPowerLoad("motor3phi",7.5,"PAC","summer"))
  LoadList.append(createPowerLoad("motor3phi",2.2,"PACFan","annual"))
  LoadList.append(createPowerLoad("motor3phi",2.2,"CoolWaterCirculationPump","summer"))
  LoadList.append(createPowerLoad("motor3phi",1.5,"CoolingTower","summer"))
  LoadList.append(createPowerLoad("heater",2.0,"Boiler","winter"))
  LoadList.append(createPowerLoad("motor3phi",2.2,"HotWaterCirculationPump","winter"))
  LoadList.append(createPowerLoad("motor3phi",3.7,"FirePump","annual"))
  LoadList.append(createPowerLoad("motor3phi",7.4,"LiftingPump","annual"))
  LoadList.append(createPowerLoad("machine",9.5,"Elevator","annual",10.0/9.5))
  LoadList.append(createPowerLoad("machine",19.0,"machine","annual",1.25,40))
  #負荷を遮断機に突っ込む
  MCCBList.append(createMCCBLoad(LoadList[0]))
  MCCBList.append(createMCCBLoad(LoadList[1]))
  MCCBList.append(createMCCBLoad(LoadList[2]))
  MCCBList.append(createMCCBLoad(LoadList[3]))
  MCCBList.append(createMCCBLoad(LoadList[4]))
  MCCBList.append(createMCCBLoad(LoadList[5]))
  MCCBList.append(createMCCBLoad(LoadList[6]))
  MCCBList.append(createMCCBLoad(LoadList[7]))
  MCCBList.append(createMCCBLoad(LoadList[8]))
  MCCBList.append(createMCCBLoad(LoadList[9]))
  MCCBList.append(createMCCBLoad(MCCBList[0:4]))
  MCCBList.append(createMCCBLoad(MCCBList[4:6]))
  MCCBList.append(createMCCBLoad(MCCBList[6:7]))
  MCCBList.append(createMCCBLoad(MCCBList[7:8]))
  MCCBList.append(createMCCBLoad(MCCBList[8:9]))
  MCCBList.append(createMCCBLoad(MCCBList[9:10]))
  #MCCBList[16]はトランス直近にMCCBを仮想的に置いたものとして与える。
  MCCBList.append(createMCCBLoad(MCCBList[10:16]))
  #負荷すべてとトランス点での最大需要電力を表示する
  tMCB=MCCBList[16]
  count=0
  for i in tMCB["LoadList"]:
    print count,"\n",i["ElectricLoadType"],"kW",i["LoadkW"],"\n",\
    u"入力換算率",i["TranslateLoadConst"],u"入力",i["TranselateVA"],"\n",\
    u"DF",i["DF"],u"最大需要電力",i["MaxDemandkVA"],u" kW","\n"
    count+=1
  del count
  print u"トランス点最大需要電力",tMCB["MaxDemandkVA"]," kVA"
  #トランスを選定して出力する
  t=createTranse(tMCB,0.0)
  print u"トランスサイズ ",t["TranseSize"]," kVA"

出力

>ipython sample150125.py
0
motor3phi kW 7.5
入力換算率 1.25 入力 9.375
DF 80 最大需要電力 7.5  kW

1
motor3phi kW 2.2
入力換算率 1.25 入力 2.75
DF 100 最大需要電力 2.75  kW

2
motor3phi kW 2.2
入力換算率 1.25 入力 2.75
DF 100 最大需要電力 2.75  kW

3
motor3phi kW 1.5
入力換算率 1.25 入力 1.875
DF 100 最大需要電力 1.875  kW

4
heater kW 2.0
入力換算率 1.0 入力 2.0
DF 0 最大需要電力 0.0  kW

5
motor3phi kW 2.2
入力換算率 1.25 入力 2.75
DF 0 最大需要電力 0.0  kW

6
motor3phi kW 3.7
入力換算率 1.25 入力 4.625
DF 0 最大需要電力 0.0  kW

7
motor3phi kW 7.4
入力換算率 1.25 入力 9.25
DF 30 最大需要電力 2.775  kW

8
machine kW 9.5
入力換算率 1.05263157895 入力 10.0
DF 80 最大需要電力 8.0  kW

9
machine kW 19.0
入力換算率 1.25 入力 23.75
DF 40 最大需要電力 9.5  kW

トランス点最大需要電力 35.15  kVA
トランスサイズ 50  kVA