複数のモジュールそれぞれがKvLanguageで同じ名前のWidgetを定義した時に起こる事

Python自体がプログラムをモジュール化して名前空間の汚染を防ぐ仕組みを持っていても、KvLanguageにおいてはその恩恵にあずかれないようです。以下のプログラムで検証してみました。

# KvLanguageで書いた部分は合成される

以下はimportした複数のモジュールが、同じ名前のWidgetをKvLanguageで定義していた時にどうなるか確かめるプログラムです。

#### mywidget_a.py

```python3:mywidget_a.py
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout


Builder.load_string(r"""
<MyWidget>:
    Button:
        text: r'mywidget_a'  #
        size_hint: 0.3, 0.1
        pos_hint: {r'center_x': 0.25, r'center_y': 0.5}  #
""")


class MyWidget(FloatLayout):

    def __init__(self, **kwargs):
        super(MyWidget, self).__init__(**kwargs)
        print(r'mywidget_a')  #


if __name__ == r'__main__':
    runTouchApp(MyWidget())
```
一旦、単独で実行

```:標準出力
mywidget_a
```
![Screenshot at 2016-11-12 12:07:45.png](https://qiita-image-store.s3.amazonaws.com/0/144673/c8b351d4-6828-33bb-b012-11a5d8721f45.png)

#### mywidget_b.py

```python3:mywidget_b.py
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout


Builder.load_string(r"""
<MyWidget>:
    Button:
        text: r'mywidget_b'  #
        size_hint: 0.3, 0.1
        pos_hint: {r'center_x': 0.75, r'center_y': 0.5}  #
""")


class MyWidget(FloatLayout):

    def __init__(self, **kwargs):
        super(MyWidget, self).__init__(**kwargs)
        print(r'mywidget_b')  #


if __name__ == r'__main__':
    runTouchApp(MyWidget())
```
同じく、単独で実行

```:標準出力
mywidget_b
```
![Screenshot at 2016-11-12 12:13:39.png](https://qiita-image-store.s3.amazonaws.com/0/144673/6cda2c83-2d72-baaa-3647-0e4737b9816c.png)

#### 同時にimportすると

```python3:both.py
from kivy.base import runTouchApp
import mywidget_a
import mywidget_b

runTouchApp(mywidget_b.MyWidget())
```

```:標準出力
mywidget_b
```
![Screenshot at 2016-11-12 12:20:05.png](https://qiita-image-store.s3.amazonaws.com/0/144673/c0852d14-8d40-5bec-507e-7b0076635c18.png)
\_\_init__はmywidget_bのものだけが呼ばれている(期待通り)のに対し、子Buttonはmywidget_aのものまで作られてしまいました(期待通りではない)。念のために[Consoleというツール](https://kivy.org/docs/api-kivy.modules.console.html)を使ってみると
![Screenshot at 2016-11-12 12:36:17.png](https://qiita-image-store.s3.amazonaws.com/0/144673/e25967ac-006a-d3c0-1342-c6a54ddd9aeb.png)
間違いなく合成されています。ということは

#### このままだと
合成を防ぐためにプログラム全体に渡ってWidgetのクラス名がかぶらぬ様に気を付けなければならないということになります。
最悪の場合はモジュール名を頭に付けてMyWidgetA_MyWidget,MyWidgetB_MyWidgetのような感じになるかもしれません。
なんとかそうしなくて済む方法はないでしょうか。

# kivy.factory.Factory
どうやらこいつがKvLanguageにおけるWidgetの生成に関わってるようです。実際に使ってみます。
まず上のboth.pyは以下のように書く事ができます。

```python3:both.py
from kivy.base import runTouchApp
from kivy.factory import Factory
import mywidget_a
import mywidget_b

runTouchApp(Factory.MyWidget())
```

```:標準出力
mywidget_a
```

又、mywidget_a.pyは以下のように書くことができます。

```python3:mywidget_a.py
from kivy.base import runTouchApp
from kivy.factory import Factory


class MyWidget(Factory.FloatLayout):

    def __init__(self, **kwargs):
        super(MyWidget, self).__init__(**kwargs)
        button = Factory.Button(
            text=r'mywidget_a',
            size_hint=[0.3, 0.1],
            pos_hint={r'center_x': 0.25, r'center_y': 0.5})
        self.add_widget(button)
        print(r'mywidget_a')

if __name__ == r'__main__':
    runTouchApp(Factory.MyWidget())
```

見るとButtonやFloatLayoutがそれぞれのimport文無しで利用できているのが分かります。普通は

```python3:
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
```
の様に利用するものだからです。他にもKvLanguage内で利用できる物はほとんどこのFactoryから利用できるようになっています。この[Package名やModule名が必要無いという利便性]の代償として、[別ModuleのWidgetとの名前衝突に気を付けなければならないという労]を払うと考えればいいのでしょうか？とにかく名前がかぶっていても何も言わないのでやっかいです。

# どうやって名前の衝突を避けるか

FactoryにはunregisterというMethodがあり、最初はこれで合成を避けれると思ったのですが違いました。

```python3:both.py
from kivy.base import runTouchApp
from kivy.factory import Factory
import mywidget_a
Factory.unregister(r'MyWidget')  # mywidget_aのMyWidgetを登録解除？
import mywidget_b

runTouchApp(Factory.MyWidget())
```

```:標準出力
mywidget_b
```
![Screenshot at 2016-11-12 12:20:05.png](https://qiita-image-store.s3.amazonaws.com/0/144673/c0852d14-8d40-5bec-507e-7b0076635c18.png)

というわけで解決できませんでした。