はじめに
業務でDjangoのManager周りのコードを読んでいると
見慣れないtype()
の使い方を見つけました。
GitHubのリンクはこちら
@classmethod
def from_queryset(cls, queryset_class, class_name=None):
if class_name is None:
class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
return type(class_name, (cls,), {
'_queryset_class': queryset_class,
**cls._get_queryset_methods(queryset_class),
})
typeに引数が三つ渡されている...???
なんだこれ?
調べてみた所、ちゃんとPython標準ライブラリのドキュメントに書いてありました。
(そりゃそう)
ほとんど引用に近い形にはなりますが、軽くまとめてみることにします。
結論
type()は引数の数によって挙動が変わる。
1.(恐らく)よくある使い方
引数が1つだけの場合、object の型を返します。返り値は型オブジェクトで、一般に object.class によって返されるのと同じオブジェクトです。(Pythonドキュメントより引用)
>>> class Bar:
... pass
>>> class Foo(Bar):
... pass
class Bar
とこれを継承したclass Foo
を用意します。
この時type()の挙動は以下のようになります。
>>> foo = Foo()
>>> type(foo)
<class '__main__.Foo'>
>>> type(foo) is Foo
True
>>> type(foo) is Bar
False
場合によってisinstance()
と使い分けましょう。
というのが自分の知っている話でした。
2.知らなかった使い方
class type(name, bases, dict)
引数が 3 つの場合、新しい型オブジェクトを返します。本質的には class 文の動的な形式です。
(Pythonドキュメントより引用)
ドキュメントでは以下の二つの文は同じtypeオブジェクトを作ると書かれています。
>>> class X:
... a = 1
>>> X = type('X', (object,), dict(a=1))
第一引数: 生成するクラス名
第二引数: 継承するクラス
第三引数: オブジェクトの属性
となっています。
実際に試してみます。
>>> class Bar:
... a=1
...
... def print_hogefuga(self):
... print('hogefuga')
...
>>> Foo = type('Foo', (Bar,), dict(b=2))
>>> foo = Foo()
>>> foo.print_hogefuga()
hogefuga
>>> foo.a
1
>>> foo.b
2
このようにBarClassを継承するFooClassを作ることが出来ました。
まとめ
以上、自分が知らなかったtype()
の使い方についてでした。
type()
以外にも驚きの使い方のものはたくさんありそうですね。
参考・引用
-
Pythonで型を取得・判定するtype関数, isinstance関数
- よく使われる
type()
,isinstance()
の解説がされています。
- よく使われる
-
Python組み込み関数ドキュメント/#type
- 個人的には使ったことがないものもたくさんあって面白かったです。いい機会なので見直します。