プログラミングのネタ帳

30代からプログラミングをはじめた。記憶力が悪いのでメモ代わりに。

pythonの readline() 関数で、最終行の判定の仕方

ファイルの読み出しには一行ずつ読めるreadline()を使うことが多いと思います。

私はこれまでは、

tmp="tmp"

while(tmp):

    tmp=f.readline()

のようにしていました。

文末でfalse的なものを返すのだろうと想像はしていたのですが、あまりエレガントではないので(一行目が)調べてみました。

 

readline()の最終行では空白行を返しているようです。

では行間の空白行はどうなるのかというと、改行コード '\n' があるので1文字とカウントするため文末にはならないとのこと。(下記リンク、7.2.1章参照)

7. 入力と出力 — Python 3.9.2 ドキュメント

 

振る舞いのテストコードを作ってみました。

最終行では0文字であること、空白行でも1文字あることが分かります。


#readline()のふるまいを確認するプログラム
#空白行でも改行コード \n があるので、1文字としてカウントされる 
#ファイルの終わりでは文字数が0になるので、そのタイミングでbreakし終了する
def check_readline_behave():
    with open("text.txt","r") as f:
        while(1):
            tmp=f.readline()
            print("this line have",len(tmp),"char data:",tmp,end="")
            if(len(tmp)==0):
                print("")
                break

#テストデータ生成用のプログラム 
#以下の例では
#1行目: 1
#2行目: 
#3行目: 2 3
def make_test_data():
    with open("text.txt","w") as f:
        print("1",file=f)
        print("",file=f)
        print("2 3",file=f)

if __name__=="__main__":
    make_test_data()
    check_readline_behave()
 
実行結果
this line have 2 char, data: 1
this line have 1 char, data:
this line have 4 char, data: 2 3
this line have 0 char, data:
    

 

上記例でいうと、最終行でtmpは空白となるので、

if(not tmp):break

 

とすることでループを打ち切られます。

 

C の構造体でリスト形式のデータ構造をつくる

アルゴリズムやデータ構造の勉強もした方がいいのだろうなと思ってちょくちょくやっています。

そして、同時にC実践プログラミングも読み進めていて、構造体で表題のことができるのかと感心しました。

 

構造体のポインタで操作するので慣れるまではだいぶ苦労しましたが、実際、絵でかいてみるのがいいかもしれません。

慣れてきて思ったことは、

・メモリの行先を常に把握し(構造体の先頭なのか、構造体の変数なのか)、指示する

・実装上同じ名前の変数で新しくメモリを確保するので、ポインタを一時保管する必要がある

というところ。半ばパズルなのだなと思いました(プログラミングがそもそもそういうものだと言われればそうですが。)

 

以下はおそらく最もシンプルであるろう方向のリストの実装です。

しかし、

・行先の構造体データのメモリ確保する際に同じ変数名を使うため、ひとつ前の構造体のアドレスをtmp_ptrで保管したり、

・whileの中でデータの代入を完結するために dummy_ptr ( malloc()でメモリ上に実体のある) を使用したりと工夫はあります。 


#include 
#include 
#include 

//構造体の宣言
struct tfield{
    char hantei[8];
    int score;
    struct tfield *pointer;
};

//プロトタイプ宣言
struct tfield *genlist();
void display(struct tfield *p);

int main(){
    struct tfield *p;
    //リストを生成する関数、
    //引数:なし 戻り値:リスト先頭のアドレス
    p=genlist();

    //リストの先頭のポインタを与えるとNULLになるまで表示する関数 
    //引数:リストの先頭のアドレス 戻り値:なし
    display(p);
}

struct tfield *genlist(){
    int i=0;
    int array_score[]={90,80,70,60};
    char array_hantei[][2]={"A","B","C","D"};
    struct tfield *head_ptr,*mydata_ptr,*dummy_ptr;
    
    //実体のあるdummyを作ることで、dummpy->pointerを使用できる
    //これを挟むことでwhileの中でmydataを繰り返し使える
    dummy_ptr=malloc(sizeof(struct tfield));
    //リストの先頭のアドレスは後々displayの際に使用するので保管する
    head_ptr=dummy_ptr;
    while(1){
        mydata_ptr=malloc(sizeof(struct tfield));
        //データの代入
        strcpy(mydata_ptr->hantei,array_hantei[i]);
        mydata_ptr->score=array_score[i];
        
        //dummyu->pointerにmydataの先頭のアドレスをいれて、
 //_dummy->pointer次のデータにアクセスできるようにする
        dummy_ptr->pointer=mydata_ptr;
        //dummyポインタに次のデータ(mydata)のアドレスを格納する(更新する)
        dummy_ptr=mydata_ptr;

        if(strcmp(mydata_ptr->hantei,"D")==0){break;}
        i=i+1;  //配列のカウンタ用
    }
    mydata_ptr->pointer=NULL;
    return head_ptr;
}

void display(struct tfield *p){
    while(1){
        //dummy_ptrの中身はみなくていいので、いきなりp->pointerとしている
        p=p->pointer;
        printf("%s %d %p \n",p->hantei,p->score,p->pointer);  
        if(p->pointer==NULL){break;}
    }
}
 
実行結果
A 90 0x56173d88c2e0 
B 80 0x56173d88c300
C 70 0x56173d88c320
D 60 (nil)

Anacondaを再インストールしたら、anaconda-navigatorが動かなくなった話

私は仮想環境の設定をよく理解できていません。

例えば、私は、お手軽に化合物のモデル化ができるRDKitを使っており、本家サイトではcondaを使ったインストールを推奨していたのでその通りにしました。ついでにJupyter-notebookを使うと可視化も容易なのでAnaconda3(Windows版)を導入した次第です。

一方で私の開発環境のベースは、WSLなのですね。理由はお気軽にlinux(bash)コマンドを使えるから 。テキスト操作に便利なのでここはこだわりたい。

そうなると上記のWindows版anacondaがうまく動かず、今まではだましだましJupyter-notebook上で動かしていたのですが、今日が割と暇だったのでよしいっちょ取り組んでみるかと試していたのですが、なかなかドツボにはまりました。

結論は、

Windows環境なのだから、Anaconda-navigatorなりJupyter-notebookはWindows版anacondaを使う

コマンドラインで使いたいのならLinux版AnacondaをWSLにいれて環境を整える

理由としては、

Linux版AnacondaはnavigatorなりJupyter-notebookがうまく開かない

・WSL上からWindows版anaconda の環境を読み込めないため

です。上記二つを解決できないのはわたしの力量不足?そもそも不可能?ひきつづきいい方法はないのかなと探っていきたいものです。

 

で、ごちゃごちゃといじっている内に、題名にあることが起きてしました。

これにはまった理由としては、アンインストールする際にコマンドライン設定の解除

conda init --reverse

をせず、そのままアンインストールしたせいの模様。

きちんとしたアンインストール方法と手動でのコマンドライン設定の解除方法が載っておりました。

Windows版Anacondaのインストール: Python環境構築ガイド - python.jp

上記サイトでは各OSでのAnaconda導入方法もわかりやすく解説してあります。

ネットでは開発環境については情報が錯そうしている感があります。

上記サイトは特段pythonの公式サイトではないようですが(そのような外観ですが)、きちんとした説明がなされていて参考になりました。

 

ついでにRDKitのインストール方法はこちらのサイトに記述あり

Installation — The RDKit 2020.09.1 documentation

とはいっても単に以下のコマンドを実行するだけ

conda activate 状態で

conda create -c rdkit -n my-rdkit-env rdkit

 

環境呼出しは、

conda activate my-rdkit-env

 

導入した環境を見るには

conda config --show envs_dirs

で表示されるディレクトリ以下を参照 (conda config --show で色々な設定を見られます)

pubchempy でsmilesとcidを指定してcompoundオブジェクトを取得する

色々あるのだろうけど、簡単な方法として二通りを紹介。

pubchempy.get_compounds(identifiernamespace=u'cid'searchtype=Noneas_dataframe=False**kwargs)

or

compoundオブジェクトの

classmethodfrom_cid(cid**kwargs)

 

試しにデカンを取得してみます。

まずは前者のget_compounds()関数から


import pubchempy as pcp

cmp_list=pcp.get_compounds(identifier="CCCCCCCCCC",namespace="smiles",searchtype=None,as_dataframe=False)
#返されるのはリスト型なので注意
print(cmp_list,type(cmp_list))
#各要素はcompoudオブジェクト
cmp_obj=cmp_list[0]
print(cmp_obj,type(cmp_obj))
#compoundオブジェクトのプロパティの一部
print(cmp_obj.iupac_name,cmp_obj.canonical_smiles,cmp_obj.molecular_formula,cmp_obj.cid)
    

実行結果は以下の通り

[Compound(15600)] <class 'list'>
Compound(15600) <class 'pubchempy.Compound'>
decane CCCCCCCCCC C10H22 15600

 

つづいて後者のCompoud.from_cid()を使う。

上記の結果から、デカンのcidは15600のようなので、芸がないようですが同じ結果を表示させてみる


cmp_ojb=pcp.Compound.from_cid(15600)
print(cmp_obj,type(cmp_obj))
#compoundオブジェクトのプロパティの一部
print(cmp_obj.iupac_name,cmp_obj.canonical_smiles,cmp_obj.molecular_formula,cmp_obj.cid)

結果

Compound(15600) <class 'pubchempy.Compound'>
decane CCCCCCCCCC C10H22 15600

 

 

詳しくは公式のリファレンスを読まないといけない。

compoudオブジェクトのプロパティとか詳細がある。

 

pubchempyの公式ドキュメントはこちら

PubChemPy documentation — PubChemPy 1.0.4 documentation

上記の方法の関数が書いてある箇所はこちら

API documentation — PubChemPy 1.0.4 documentation

 

この記事が初めてのエントリだったりします。

しょっぱななのにマニアックなネタですね・・・。

しかし、やってることは最も簡単なことで、化学屋さんに役に立てればと思います。

 

本ブログの目指すところ

メインのテーマは題名の通りプログラミング。

その日に勉強したことや思ったことを書いていく。

自分用のメモ用途と、自習したことのアウトプットが目的です。

 

いま(2021年3月)に興味がある分野は以下に列挙する分野で、このあたりについて記事を書いていくことになると思います。

・基本をしっかり押さえたいのでC,C++

・おもにC(C++)を使ってでアルゴリズム

・ExcelVBA

・これにともなってVisual Basic

・流行りのpython

pythonまわりのモジュール

他には

・計算機科学に興味があるので、それ周りのソフトウェア

・基本情報、応用情報の勉強もすこしずつ

 

今の私は会社員をしていますがITと関係ないし、業務中にプログラミングもやらない。

なので、家に帰ってから(あるいは行き帰りの電車の中で・往復で2時間)でしかやる時間がないです。

平日も少しずつ進めるためにプログラミングを触るとは思いますが、記事にまとめ切れるかは、・・・。

そうなったら土日にまとめて記事にしたいものです。