LoginSignup
0
1

More than 1 year has passed since last update.

Python学習記録_3日目.オブジェクト・モジュール・パッケージ

Last updated at Posted at 2022-04-25

元記事

Python学習記録_プログラミングガチ初心者がKaggle参加を目指す日記
3日目。
2日目はリストとrange型オブジェクトの違いに心を折られかけましたが今日も頑張っていきましょう。

標準入力と標準出力 10m …

input関数とprint関数の使い方についてのおさらい?でした。
複数の変数をまとめて出力する時は
print(変数名1,変数名2,変数名3…)
という形で記述するとまとめて出せるみたいです。

Python 関数 戻り値とは 15m …

このテキストでは、プログラミングにおける関数の戻り値と呼ばれる内容を学びます。
本テキストで学ぶ内容は、初学者からすると理解し難い内容の1つであるため、1回読むだけですと理解できない場合があります。そのため理解出来るまで何度も読み返してみてください。
また、大変重要な内容ですので是非最後まで頑張って読み進めてみてください。

初っ端から不穏な空気が…

戻り値(返り値)

戻り値(返り値)とは、プログラム中で呼び出された関数などが処理を終了する際に、呼び出し元に対して渡す値のことです。
つまり、戻り値とは関数から呼び出し元へデータを渡す仕組みになります。

引数とreturn

先ほど、戻り値(返り値)とは何かを説明しましたが、returnを関数内に記述すると、関数内の処理を終了し、呼び出し元にデータを渡すことが出来ます。
(一般的に独自関数を作る場合に、returnを記述することがほとんどです。)
またreturnは関数内であれば任意の場所に記述出来ます。returnが実行されると関数内の処理はそこで終了となりますので注意です。さらにreturnは複数記述することも可能です。
本セクションで学ぶreturnは一般的に関数内でのみ用いられます。

専門用語を事前説明なしに当たり前のように使うのやめろ
タイトルに「引数」なるものがでてきました。
どうも戻り値と関係の強いワードらしいので「引数 戻り値」でググってみると

引数は「大根」、戻り値は「大根おろし」
非常に分かりやすいサイトがありました。
「引数」という材料・素材を元に「関数」という処理・加工を行い「戻り値」という結果を返す、ということのようです。

def adder(a,b):
    return a+b 
value = adder(3,7)
print(value)
 # 出力結果 10

つまりここでは(3,7)が引数、a+bが関数、10が戻り値ということですね、ふむふむ。
def 関数名(引数1,引数2)
  return 戻り
というのが構文。
ちなみに戻り値を省略するとNoneが返ってきます。

なぜreturnを使うのか

そもそも関数内でなぜprint()関数ではなく、returnを使うのかという点がプログラミングを学び始めの頃にはいまいち理解し難いです。
大前提として、print()関数とreturnは全くの別物なため、しっかり使い分けが出来るようにする必要があります。

たしかに上の例だと

def adder(a,b):
    print(a+b) 
value = adder(3,7)
print(value)
 # 出力結果 
 # 10
 # None

でも同じ結果になりそうなのにわざわざreturnを入れる意味はないように思えました。
結果的には謎のNoneが出てきたわけですが…

2つの違いとしては次の通りです。

  1. returnは値を返すことが目的(一般的に独自関数を定義する場合の多くに利用します。)
  2. print()関数は値を出力すること目的

つまり、returnを使う理由として、「値を呼び出し元に返す必要がある場合に使用する」ということになります。

上記のコードですが、関数というものは必ず出力が必要なので、自動的に内部でreturn Noneという処理が追加されています。
関数内でprint()関数を利用せずに、returnを用いる事で、Noneという値は返されず、計算結果のみを変数sum_valueに代入する事が出来ます。(returnで返している値は、a+bだからです。)

なるほど、関数は必ず出力が必要になるというのが多分ミソですね。
つまり関数の中に関数を入れてしまうと2つ出力する必要が出てくる、みたいな感じだと思う。

returnを用いたプログラムに慣れよう
def a(a,b):
    return a + b

def b(a,b):
    return a * b

x = a(2,2) # xに4が代入
y = b(x, x)  # 4 * 4

print(y) # 16が出力される

関数bでは、前の関数aの処理結果xを受け取り、引数に渡しています。
このように、returnを用いることで計算結果を一旦変数に格納することができ、さらにその値を別の関数に渡して違う処理に繋げることが出来ます。
また、関数に渡すというのはreturnを使う一例ですが、関数に渡さない場合でも、戻り値(返り値)に対して更に何かしらの処理を行うことが出来るということがポイントになります。
関数内部でprint()関数にて出力するだけであればprint()関数を用いて値を出力すれば良いですが、内部にprint()関数が無い関数は処理した結果をreturnで返し、受け取ったその値を変数に代入し、また他の関数にその戻り値を渡すといった流れで、再度別の処理につなげる事が出来るようになります。
前述の通り、returnは値を返すことが目的であるため、関数内部の処理を関数内部の処理以降のプログラムでも、戻り値として受け取った値を使用することが前提となっています。

print()を使って出力をしてしまうとその戻り値を別の関数に代入する時手間だけど
returnで戻り値としての結果を別の関数に使えるよ!ってことかな。
最終的に何かを出力するコードを書く場合でも過程を出力する必要はないからreturn使うべき、というような理解。

def power(x):
    return x*x

def absolute(x):
    if (x < 0):
        return -x
    else:
        return x

power_value = power(10) # 100がpower_valueに代入されている
absolute_value = absolute(-10) # 10がabsolute_valueに代入されている

 # 上記の計算結果を格納した変数をif文などで比較して処理を分岐させたりする事が出来ます。

上記のようにただ値を出力するのではなく、一度変数に計算結果を代入する事で、その値を他の関数の引数に渡して別の処理に繋げるといった具合に、次の処理に繋げる事がreturnを用いるメリットの1つです。

この例もprint()にしてるとここで作ったpower_valueやabsolute_valueが他の関数で使えないよ、ってことですね。
とにかく次の処理がある場合には戻り値として保管しておくのが良さそうなイメージです。

演習問題

1)繰り返したい文字と繰り返したい回数の2つの変数を渡すと繰り返したい回数分の文字が返される関数を作成して下さい。

def re_text(a,b):
    return a*b
print("繰り返したい文字")
a=input()
print("繰り返したい回数")
b=int(input())
c=re_text(a,b)
print(c)

回答見たら関数だけ作ればOKでした。
あとは繰り返しなのでfor文を使ってもできるとのことで

def re_text(a,b):
    for i in range(b):
        print(a)
print("繰り返したい文字")
a=input()
print("繰り返したい回数")
b=int(input())
re_text(a,b)

でもいけました。なるほど…

Python クラスとオブジェクト 25m …

完全に意味不明なワードメガ盛りコースでした
インスタンスとオブジェクトの違いとか全然ピンと来ないので色んなサイト回りました。
クラス・インスタンス・オブジェクトの違いは神の気分になるとわかる
オブジェクトとインスタンスって何が違うの?という初心者プログラマー向けの図解
インスタンスもクラスもオブジェクトの一種でクラスを使ってインスタンスを作る、以上!
ってくらいのノリで進めます。

はじめに

Pythonはオブジェクト指向プログラミング言語の1つです。
この章ではオブジェクト指向プログラミング言語の理解には欠かせない、「クラス」の基本に関して説明します。
Pythonに限らず、オブジェクト指向プログラミング言語には「クラス」を使うことが出来ます。
オブジェクト指向は理解がしにくいものです。このテキストだけで全てを理解しようとせず、こういうものなんだなという程度の理解で構いませんので、自分のペースで学習を続けてください。

今までも相当理解しにくかったのにこんな前置きがあるの怖すぎる

オブジェクト指向とは

オブジェクト指向とはプログラミングのスタイル・手法のことで、プログラミングパラダイムと呼ばれる1つです。
プログラミングパラダイムには、オブジェクト指向(オブジェクト指向プログラミング)以外にも、関数型プログラミング、手続き型プログラミングがあります。
オブジェクト指向は開発の効率や保守性を上げることが出来ます。
オブジェクト指向を活用可能なプログラミング言語には、PythonやJava、C++といった言語が挙げられます。
この章では、Pythonを用いてオブジェクト指向の基礎となるクラスを説明していきます。

クラスとは

クラスとはデータ構造を作る仕組みで、クラスを使うと新しいデータ型を作ることができます。
一般的なクラスの説明として、オブジェクトを作る設計書と説明される事が多いのですが、「クラスがオブジェクトを作る設計書である」という説明だけではクラスの概念を理解し難いかと思います。
そのためこの章では、クラスとインスタンスの関係を表した下記のイメージ図を元に説明します。
image.png

クラス(データ構造を作る仕組みで設計図)を元に、インスタンス化(たこ焼きを焼く・作る)を行う事によりインスタンス(別名:オブジェクト)を作成します。
インスタンス化というのはクラスからインスタンス(別名:オブジェクト)を作ることです。

バカにしてんのか???ってくらいにワードが頭に入らない…
今のところ理解できたのはクラスを使ってインスタンスを作るってこととインスタンス≒オブジェクトってことくらいなんだが…

いったんはオブジェクトってものの中にインスタンスがあって、そのインスタンスを作るためのものがクラスである、くらいの理解で進めます

オブジェクトとは

オブジェクトとはデータ(属性)とメソッド(クラスに定義された関数)を持ったものです。
Pythonの値は全てオブジェクトであり、オブジェクトには実行で出来る関数(メソッド)が定義されています。

メソッドとは

メソッドとはクラス内に定義された関数の事です。
メソッドには初期化メソッドと呼ばれる特殊なメソッドも存在します。

クラス外に定義される関数もあるってことなんですかね…?

クラス変数とは

クラス変数とは、すべてのインスタンス間で共通した値をもつ変数です。
クラス変数は以下のように、クラス内に定義することで作成できます。
クラス変数にアクセス(情報を取り出す)するには以下のようにします。

class SampleClass:
    class_val = 'クラス変数'
print(Sampleclass.class_val)
 #出力結果 クラス変数

クラスを定義したあとに:を打ってインデント、変数=入れたい値でクラス変数を作れると

クラス変数にアクセスする

クラス変数にアクセスするにはクラス名.クラス変数と記述します。
クラス変数を変更すると、そのクラスからインスタンス化された全てのインスタンスのクラス変数が変更されます。
また、クラス変数にアクセスするにはクラス名.クラス変数以外にもインスタンス.クラス変数でもアクセスが可能です。

class SampleClass:
    class_val = 'クラス変数'
    
print(SampleClass.class_val) # クラス変数

# クラス変数を変更する
SampleClass.class_val = "変更2"
print(SampleClass.class_val) # 変更2

=は「等しい」ではなく代入だから変数の中身を変える時も=でOK、これは前に習ったところですね。

class SampleClass:
    class_val = 'クラス変数'

sample = SampleClass()

sample.class_val = "クラス変数2"
print(sample.class_val) # クラス変数2
print(SampleClass.class_val) # クラス変数

この例文で言うとsampleがインスタンスで、sample.class_valがインスタンス.クラス変数ですね。
インスタンスで指定するとクラス変更を変更することはできないのでsampleインスタンスは変数2に代わってるけどクラス変数であるSampleClass.class_valは変わってない、ということ。
インスタンスの指定でクラス変数を変更したいときはインスタンス.class.クラス変数の書き方が必要で

class SampleClass:
    class_val = 'クラス変数'

sample = SampleClass()
sample2 = SampleClass()

sample._class_.class_val="クラス変数の値を書き換える"

print(sample.class_val) #出力結果 クラス変数の値を書き換える
print(sample2.class_val) #出力結果 クラス変数の値を書き換える
print(SampleClass.class_val) #出力結果 クラス変数の値を書き換える

という書き方になる。なるほどなるほど。

コンストラクタ(初期化メソッド)とは

コンストラクタとはインスタンスが生成されるときに自動的に呼び出されるメソッドのことです。
コンストラクタは対象のクラスのインスタンスを初期化するために利用します。
インスタンスを作る時に初期値を与えたい時に初期化メソッドを使うと便利です。
※Pythonでは、初期化メソッドをコンストラクタと呼ぶ場合がありますが、厳密にはコンストラクタではなく、コンストラクタから呼び出される初期化メソッドになります。
クラスには__init__という特殊なメソッドを書くことができます。
__init__が初期化を行うメソッドで、クラスのインスタンスが作成される際に一度だけ呼ばれるメソッドです。
また、クラスが内包するデータを属性と呼びます。
加え、selfとはインスタンス自身を指す用語です。メソッド内で必ず指定する必要があり、メソッドを定義する上で必須だと覚えてください。
そのため、init()という初期化関数(この関数もクラスを定義する際に必須です。)やその他メソッド(クラス内で定義された関数)を定義する際には第一引数に必ず指定する必要があります。
最後にselfの呼び方ですが「インスタンス自身」、「メソッドの仮引数」など様々な呼び方がされます。

若干カタカナがゲシュタルト崩壊起こしてます。
これ初めてプログラミングに触れる人にはハードル高くない…?

initについてはもうそういうものだ、と思っておいた方が良いものな気配。
クラスを定義する際にはとりあえず

class クラス名:
    def __init__(self,変数名1,変数名2,変数名3):
        self.変数名1=変数名1
        self.変数名2=変数名2
        self.変数名3=変数名3

が基本の構文になっている。
ちなみにinit前後のアンスコは2文字必要。(これに気づかず30分くらいエラー吐き続けてました)
ということで書いてみたのがこちらですが

class test:
  def __init__(self,name,age):
    self.name=name
    self.age=age
    
  def introduction(self):
    print("my name is {}, my age is {}".format(self.name,self.age))

a=test("taro",24)
print(test.introduction(a))
 # 出力結果
 # my name is taro, my age is 24
 # None

でNoneが出てしまった。
これは関数は何かを出力しないといけない系のエラーか…
print関数をintroductionの関数に持たせてるからいらないってことなのかな?と思い

class test:
  def __init__(self,name,age):
    self.name=name
    self.age=age
    
  def introduction(self):
    print("my name is {}, my age is {}".format(self.name,self.age))

a=test("taro",24)
test.introduction(a)
 # 出力結果
 # my name is taro, my age is 24

と無事なりました。ちょっとずつ分かってきた気がする。
けど上のクラス変数の例文ではinit使ってないのにclass_valっていう変数の定義ができてたのはなんでだろう…
多分厳密に言うとなくても定義できるけどあった方が色々捗る系のやつだと思っておいて先に進めます。

インスタンス変数とは

インスタンス変数は、個々のインスタンスに格納される変数のことです。

class User:
    # 実行順②
    def __init__(self, name): # インスタンス化されて渡ってくる値を受ける変数を定義します
        # インスタンス変数(属性の初期化)
        self.name = name # 実行順③
        print("コンストラクタが呼ばれました") # # 実行順④

    def hello(self):
        print("Hello " + self.name)
        
user = User("Sample User") # userというインスタンスを生成しています。 実行順①

今回定義したUserクラスのコンストラクタはnameという引数を取り、その引数で変数であるself.name(この変数のことをインスタンス変数と呼びます)を初期化しています。
インスタンス変数は、個々のインスタンスに格納される変数のことですので、ここでは5行目のnameがインスタンス変数です。
8行目に定義したhelloメソッド内9行目で、selfの後ろに属性名nameを書いていますが、このように.インスタンス変数名と書くことで、インスタンス変数の作成及びアクセスができます。

微妙にクラス変数とインスタンス変数がこんがらかってきた…
自分で書いたやつを例にとると

class test:
  def __init__(self,name,age):
    self.name=name
    self.age=age
    
  def introduction(self):
    print("my name is {}, my age is {}".format(self.name,self.age))

a=test("taro",24)
b=test("hanako",28)
test.introduction(a)
test.introduction(b)
 # 出力結果
 # my name is taro, my age is 24

これはクラス変数を定義してないな…?
それっぽくクラス変数定義するなら

class test:
  test_int="hello,my name is " 

  def __init__(self,name,age):
    self.name=name
    self.age=age
    
  def introduction(self):
    print("{}{}, my age is {}".format(test.test_int,self.name,self.age))

a=test("taro",24)
b=test("hanako",28)
test.introduction(a)
test.introduction(b)
 # 出力結果
 # hello,my name istaro, my age is 24
 # hello,my name ishanako, my age is 28

こういうことかなと理解。
クラスに持たせた方が良い変数とインスタンスごとに持たせた方が良い変数が今は曖昧だけどこれは実際にコード書けるようになると分かるようになるんだろうな…

クラスを使用することによる利点

クラスを使用することによる利点は、コードの可読性が向上し、ミスを未然に防げたり、チームで開発するときなどの共有が楽になることです。
例えば、直近1週間の売上から当日の売上を予測するAIプログラムを作る際にクラスを使用することを考えます。
考えられる処理として以下のような機能が考えられます。
1週間の売上を読み込む
1週間の売上を学習する
当日の予測を出力する
それぞれの処理を以下のメソッド名で実現出来るようします。
1週間の売上を読み込む -> read_data()
1週間の売上を学習する -> train_data()
当日の予測を出力する -> predict()
ばらばらに使ってもプログラムとしては動きますが、これらは一連の処理なので、まとめることで可読性を上げることができます。上記の処理を含むクラムを以下のようにSalesPredictionというクラスにまとめられます。

class SalesPrediction:
    # 売上予測AI用のデータを読み込む
    def read_data():
        pass
    # 売上予測AIの学習
    def train_data():
        pass
    # 売上予測AIをつかって当日の予測をする
    def predict():
        pass

さらにチームによる複数人開発をする際に、read_dataというメソッドだけでみると、「何のデータを読み込むのだろうか」「読み込んだデータは何に使われるんだろうか」と疑問になってしまいますが、このようにクラスで定義していると、一連の流れで使われる処理がまとめられているので、仕様書などを熟読しなくてもある程度理解をすることが可能になります。

一度クラスとして定義してしまえば後から見直してもわかりやすい的な…
ここら辺はほかのプログラミング言語に触れたことないのでいまいちメリットが分かり辛いなあ…

演習問題
  1. 生徒のテストの点数を管理するクラスを作ってください。
    コンストラクタには、scoreという変数をクラス内に定義し、scoreは辞書型で管理してください。
    例) {"english": 99, "math": 49}
  2. 会員情報を保持するUserクラスを以下の指示にしたがって作成してください
    クラス名: `User
    属性(コンストラクタで定義する、クラスが内包するデータのこと):
    会員ID(user_id)
    ユーザーネーム(username)
    メールアドレス(email)
  3. 2で作成したクラスに、get_userinfo()というメソッドを追記して呼び出してください。
    このメソッドを呼び出したら、usernameとemail`を出力してください。
 # 1
class test_score:
  def __init__(self,score):
    self.score=score
    
a=test_score({"english": 99, "math": 49})
b=test_score({"english": 70, "math": 85})

print(a.score)
print(b.score)
 # 出力結果
 # {'english': 99, 'math': 49}
 # {'english': 70, 'math': 85}

 # 2,3

class User:
    def __init__(self,user_id,username,email):
        self.user_id=user_id
        self.username=username
        self.email=email

    def get_userinfo(self):
        print(self.username,self.email)
a = User("aaa","taro","sample1@xx")
b = User("bbb","hanako","sample2@xx")
User.get_userinfo(a)
b.get_userinfo()
 # 出力結果
 # taro sample1@xx
 # hanako sample2@xx

一応できた、できたんだけど

User.get_userinfo(a)
b.get_userinfo()

1行目が自分で書いたやつ、2行目が回答例文に記載があったやつで
どちらも正しく出力はされた。
クラス名.メソッド(インスタンス名)
インスタンス名.メソッド()
って同じ結果になるものなのか…?不思議だ…

Python テキストファイルの読み書き 25m …

はじめに

ここでは、pythonを使ってテキストファイルに保存する方法を学びます。
なぜテキストファイルに保存にするのでしょうか。
例えば、チャットボード(掲示板)のようなものをpythonで作る場合、誰か何時に投稿したのかなどのデータを保存しておく必要があります。
そこで、テキストファイルに保存(書き込み)ができると、利用者のやりとりを残すことができます。
このように何かしらのデータを容易に保存することができるようになるのが一番の利点です。
実際にはデータベースなどを使ってデータを保存することができますが、データベースを利用するよりもファイル処理を使うことの方がデータを容易に保存すること出来ます。
このテキストでは、テキストファイルに文字列などをファイルに保存するプログラムを学んでいきます。

テキストファイルの読み書き

ファイル処理の流れは以下になります。

  1. fileをオープンしてfileオブジェクトを取得
  2. fileオブジェクトに対して処理を行う
  3. fileをクローズする
ファイル読み書きの決まりごと

先ほど、ファイル処理の流れとして3つの説明をしました。
この3つの決められた手順を沿ってプログラムを書く必要があります。
1) ファイルを開く => open(第一引数, 第二引数)
1)のopen()には2つ引数を渡せます。
第一引数には、ファイル名、第二引数にはモードを渡します。
open(ファイルパス, オープンするモード)
ファイルパス: 相対パス及び絶対パス
オープンするモード(デフォルトは"r")
r: 読み込みモード
w: 新規書き込みモード
a: 追加書き込みモード
ファイルオブジェクトをクローズする
2) ファイルを読み書きする => read() または write()
2)では、read()関数(読み込み)またはwrite()関数(書き込み)を使って、ファイルの処理を読み込むのか書き込むのかを決めます。
3) ファイルを閉じる => close()
3)のようにファイルを開いたら必ず最後にファイルを閉じましょう。
close()
ファイルを最後にクローズしないといけない理由に関して説明します。
多くのファイルを開いたときにわかりますが、
同時に開けるファイルの数には上限があるのでclose()で閉じるという処理を行う必要があります。
ですので、決まりごとや守らないといけないことだと思い、ファイル処理の最後には、close()を使いましょう。

GoogleColab使ってるからかファイルの読み込みができませんでした…
ちゃんと自分のPCに環境設定できるようになったら改めて読み直します

Python モジュール・パッケージ 15m …

ライブラリ

ライブラリとは、ある程度まとまった汎用性の高い処理(関数・クラス・その他)を他のプログラムから読み込むことで、使うことが出来るようにしたファイルです。
Python内では基本的にimportできるものをライブラリと呼んだりします。
なお、ライブラリは一般的な呼び名であり、Pythonでは、基本的にライブラリという表記があったら、下記で説明するモジュールのことだと思ってください。

名前を頻繁に聞くpandasとかnumpyとかはライブラリ≒モジュールということか。
よく使う処理・便利な処理を誰でも使えるようにしてるファイルってことですね。

モジュールとパッケージ

モジュールはPythonのコードをまとめたファイルであり、他のプログラムから再利用できるようにしたファイルのことを「モジュール」と言います。
公式サイトより以下引用:
Python では定義をファイルに書いておき、スクリプトの中やインタプリタの対話インスタンス上で使う方法があります。このファイルを モジュール (module) と呼びます。
それ単体では動作しませんが、importすることでモジュールが使えるようになります。
パッケージとは__init__.pyと複数のモジュールがディレクトリに集まったものです。
init.pyはパッケージディレクトリに置かれ、そのパッケージをインポートした際に実行されます。

モジュールの詰め合わせがパッケージ。
…ってことはPandasとかnumpyはパッケージ…?

モジュールのインポート

import モジュール名でインポートが可能。シンプル。
色んなインポートの仕方があって

import math
math.cos(1) # 0.5403023058681398

が基本。
ファイル名の指定なしにインポートする場合は

from math import cos, sin, tan
cos(1)

という形でfrom モジュール名 import 関数名でもインポート可能。
こうすると関数を呼び出すときにいちいちモジュール名を入力しなくても済むらしい。
関数名のところに*を入れるとすべての関数をインポート。
色々使う時はこっちの方が手っ取り早そう。

練習問題

1)Pythonの標準モジュールcalendarを読み込み、2020年1月のカレンダーを出力してみて下さい。
ヒント1:month()を利用。
ヒント2:第一引数には年を、第二引数には月を渡します。
公式リファレンス
===リファレンス引用===
calendar.month(theyear, themonth, w=0, l=0)¶
TextCalendar の formatmonth() メソッドを利用して、ひと月分のカレンダーを複数行の文字列で返します。
===リファレンス引用===

import calendar
print(calendar.month(2020, 1))

3日目の感想

オブジェクトのところでかなり時間をかけてしまってスケジュールよりも遅れてしまったものの、
なんとなくクラスやインスタンスの理解ができた。
オブジェクト指向がすごいらしいけど正直ほかの言語を触ったことがないから何がすごいか良くはわかりませんでしたが…
それぞれのクラスで保存ができるので共有がしやすい、みたいな感じかなと感じました。
モジュールって機能もオブジェクト指向だからこそ実装できた、とかだったらわかりやすくすげー!ってなります。

明日はいよいよ名前だけはよく聞くnumpyに触れると思うので楽しみ3割まともに理解できるか不安7割くらいで臨みます。
引き続きがんばれ自分

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1