JavaerからPythonistaになった時に失敗したこと

# 初めに
これは[PyCon JP Advent Calendar 2016](http://www.adventar.org/calendars/1741)の12/2担当記事です。
ほかにも面白い記事があるので、興味がある方はぜひ。
ところどころJavaを記述しているところがあるけれど、久々だから間違ってるかもしれないので、そこは雰囲気で察しながら読んでいただけると幸い。

# 目的
件名にもある通り、これを読んだ人がJavaer→Pythonistaへの移行をスムーズに行えるように、私が経験した失敗を共有しようと思う。

# 自己紹介
PyCon JP 2017のメンバー。
PyCon関連での活動でいえば、[2015ではトーク](https://www.youtube.com/watch?v=p4EElYZwZw4)をしたり、[2016ではLT](https://www.youtube.com/watch?v=O1-9Yv9cB8Q&t=820s)したりしている。
第一回[Python Boot Camp](http://www.pycon.jp/support/bootcamp.html)講師もした。
Twitterアカウントは[@horobi_gengar](https://twitter.com/horobi_gengar)

# 今までの経緯
件名の件について、必要だと思うので簡単に今まで開発で使ってきた言語の説明を最初に。

| 順番 |在籍期間|メイン言語|補足|
|:---:|:---:|:------------------:|:------------------:|
|1社目|2年半|特になし|cとかvbとか。現場に合わせて臨機応変|
|2社目|5年半|Java|他にはJavaScriptとかDelphiとかCOBOLとか|
|3社目|５ヶ月|特になし|C#やPHPをちょっとずつ|
|4社目|2年|Python|ごくまれにRubyに関わる|
|5社目|３ヶ月(継続中)|Python|たまにJavaScriptを書く|

なので、今回の話は4社目の時の話になる。

# 失敗したこと
##  １ファイル１クラスで書いてしまった
いろんな失敗をしたけれど、これが一番デカかった。
Javaは基本(例外あるけど)1ファイル１クラスで記述するが、Pythonは１ファイルに複数クラスを記述することが多い。
イメージ的にはPythonはJavaに比べてパッケージの階層が一つ減るイメージで書かなければならない。

パッケージ(フォルダ構成)のイメージと合わせて説明しようと思う。
例えば共通モジュールの中のusersテーブルにアクセスするための[DAO](https://ja.wikipedia.org/wiki/Data_Access_Object)だったら

common
　└db
　　└dao
  
というパッケージの下にUsers.javaというファイルを作成し、その中にUsersというクラスを作成する

そして、そのUsersクラスを他のクラスから使用したい場合、

```java:Users.java
package common.db.dao.Users

users = new Users()
user = users.getUser(1)
```

みたいな感じになる。
しかし　Pythonでも同様のパッケージ構成で記述してしまうと、

```py:users.py
from common.db.dao.users import Users 

users = Users()
user = users.get_user(1)
```

みたいな感じになって、fromの最後とimportの内容がかぶってしまい、助長的になってしまう。
なので、今回の場合でいうと、dbパッケージの下にdao.pyを作成し、その中にUsers　クラスを記述して、

```py:users.py
from common.db.dao import Users 

users = Users()
user = users.get_user(1)
```
という風に記述すべき。(これはこれで、ゆくゆくdaoファイルのサイズがえらいことになりそうだが、あくまで例ということで)
この失敗により、ある程度稼働実績のあるモジュールをごそっと修正することになった。


## 内部変数を全てpublicにしてしまった。
Javaの場合、クラスの内部変数の頭にpublicやprivateとつければ、外から参照できるかどうかを明示的に指定することができる。

```java:User.java

public class User{
    public int userId;　　　　　     //クラスの外からアクセス可能
    private String userName; //クラスの外からアクセス不可能
    public User(int userId, String userName){
        this.userId = userId
        this.userName = userName
  }
}

User u = new User(1, "山田太郎")
System.out.println(u.userId)  //セーフ
System.out.println(u.userName)//アウト
```

一方、Pythonの場合、変数名に『_(アンダーバー)』をつけることにより、Javaでいうpublicやprivateの制御を行うことができる。(やろうと思えば参照できるけど。)

```py:user.py
class User(object):
    def __init__(self, user_id, user_name):
        self.user_id = user_id       #クラスの外からアクセス可能
        self.__user_name = user_name #クラスの外からアクセス不可能

u = User(1, '山田太郎')
print(u.uer_id)     #セーフ
print(u.__user_name)#アウト
```

でだ、何を思ったのか、Pythonを書き始めた当時、勘違いして覚えてしまったのが、下記の言語仕様である

```py:user.py
class User(object):
    user_id = 0                    #この場所に書いておけばクラスの外からアクセス可能
    def __init__(self, user_id, user_name):
        self.user_id = user_id       
        self.user_name = user_name #書いてなければprivate扱い

u = User(1, '山田太郎')
print(u.uer_id)   #セーフ
print(u.user_name)#アウト(だと思ってた)
```
どうしてこんなことになったのか。もちろんuser_nameは外からアクセスし放題である。
これに気付いた時背中に寒気が走り、アンダーバー２個付け祭りが開催されることになった。

## getter・setterを作ってしまった。
Javaの場合、内部変数をpublicで指定せず、影響範囲等を考えて、getterやsetterを作る

```java:User.java

public class User{
    private int userId;　　　　　    //内部変数は外からアクセスできないようにしておく
    private String userName;
    public User(int userId, String userName){
        this.userId = userId
        this.userName = userName
    }
    public int getUserId(){
        return this.userId;
    }
    public int getUserName(){
        return this.userName;
    }
}

User u = new User(1, "山田太郎")
System.out.println(u.getUserId())  //内部変数を直接呼ぶのではなく、関数を挟むことにより、カプセル化する
System.out.println(u.getUserName())
```
なんせEclipseにgetter・setterを一括作成する機能があるぐらいだからね。
で、これと同じことをPythonでもやってしまった。

```py:user.py

class User(object):
    def __init__(self, user_id, user_name):
        self.__user_id = user_id
        self.__user_name = user_name

    def get_user_id(self):
        return self.__user_id

    def get_user_name(self):
        return self.__user_name


u = User(1, '山田太郎')
print(u.get_user_id())
print(u.get_user_name())#こんな感じに使う
```

Pythonのような、いわゆる軽量言語のメリットの一つに、『コード量の少なさ』というものがある。
この悪しき記述方法はそのメリットを見事に消してしまう、ベリーバッデストノウハウである。残念。
Pythonの場合だと、もうこれでいいのだ。

```py:user.py

class User(object):
    def __init__(self, user_id, user_name):
        self.user_id = user_id       #外から直接アクセスされる可能性があるなら、もうアンダーバーつけない
        self.user_name = user_name

u = User(1, '山田太郎')
print(u.user_id)
u.user_name = '鈴木二郎' #アクセスし放題だけど、これでいいのだ！！！
```

どうしても気になるならpropertyでも使えばいいじゃないってことです。

```py:user.py

class User(object):
    def __init__(self, user_id, user_name):
        self.__user_id = user_id
        self.__user_name = user_name

    @property                          #読み取り専用ならこんな感じに
    def user_id(self):
        return self.__user_id

    @property
    def user_name(self):
        return self.__user_name


u = User(1, '山田太郎')
print(u.user_id)       #セーフ
u.user_name = '鈴木二郎' #アウト！！！！
```

ちゃんと書くって大事だよね。

# あとがき
今までに何回か
「あなたの書いたPythonはJavaっぽい」
「俺Javaerなんだけど、あんたの書いたPython読みやすい」
と言われたことがあり、結構気にしていたのがきっかけで今回の記事を書いた。
やっぱり他の軽量言語をずっと書いてきた人が書いたPythonと比べると、自分の書いたPythonはどこか堅っ苦しくてJavaぽい。
もう２年Python書いてるので、Java臭はだいぶ消えてきていると思うのだが、これからも日々精進していきます。