結論から言えば「おおきく道を間違えている」といえると思います。
参照しておられるサイトは(大変失礼かつ生意気な言いようですが)Pythonの型システムの設計に踏み込んだ議論が不足していると思います。(スミマセン、元の記述は言い方がおかしかったので訂正しました)。
Pythonでは動的なインスタンスの改変をかなり「ゆるく」許しており「型を表す重要なフィールドである__class__
も場合によっては簡単に改変できる」ようになっています。しかしながら「それを変更することで何が起きるかは言語システムでは何も保証していないに近い」です。
python
1def cast(clazz, instance):
2 instance.__class__ = clazz
3
4class A:
5 def __init__(self, value):
6 self.value = value
7
8 def get(self):
9 return self.value
10
11 def __repr__(self):
12 return '#<A: value={}>'.format(self.value)
13
14class B: pass
15
16b = B()
17print(type(b)) # => <__main__.B at ...>
18case(A, b)
19print(type(b)) # => <__main__.A at ...> Aのインスタンスになったかのように見えるが
20print(b) # => 例外
21print(b.get()) # => 例外
22b.value = 1
23print(b.get()) # => 1
24print(b) # => #<A: value=1>
ちなみにcastした後、b.valueに1を設定なんてことをしてますが、それをしさえすればいいかという単純な話でもありません。classの定義のしかたによって上記のような程度ではすまず、手が付けられない状況にもなることもあるでしょう。
要するに単に__class__
を変えたらインスタンスが他のクラスに化けてくれるなんてことはありません。これはPythonの型システムを熟知したプログラマーが新たにメタクラスやそれに関連したデコレータなどのメタプログラミングをする際に使うもので、普通のアプリケーションを作る際に手をだすようなものではないと思います。
さてそもそもC#のような静的型付け言語におけるダウンキャストとは
「ある基底クラスに属するインスタンスが、そのクラスの特定の派生クラスのインスタンスであるかどうかを検査し、そうであるなら成功、そうでないなら失敗(失敗動作は例外の発生だったり、つじつまを合わせるために結果をnullにしたり)させること」です。
決して「基底クラスの派生クラスでないものを無理やり派生クラスに改変する」ようなものではありません。全然目的が違うのです。
補足: 結論を言い忘れました。(じゃなくて...)C#のasをそのまままねするなら次のようにすべきと思います。
Python
1a = some_function() # AまたはAの派生のBのインスタンスを返すような関数
2b = a if isinstance(a, B) else None
3# もしaがBのインスタンスならbにはそのインスタンスが設定されそうでなければNoneが設定される