2023 06 25
【Python】Listで削除実行時の実行時間
https://wiki.python.org/moin/TimeComplexity 参考リンク先ではDel sliceは計算量\(O(n)\) これは最悪の場合で実際は削除する量による。 PythonではListの要素を削除する際に、各要素のインデックスの再設定が行われる様子。 したがって削除された要素以降の要素が多いほど計算量が嵩むことになる。
from time import perf_counter
C = [3, 5, 7, 8]
for c in C:
l = [0 for _ in range(10**c)]
s = perf_counter()
del l[10:]
e = perf_counter()
print(f"del item [c={c}, del list[10:]]: {e - s}")
print()
for c in C:
l = [0 for _ in range(10**c)]
s = perf_counter()
del l[-10:]
e = perf_counter()
print(f"del item [c={c}, del list[-10:]: {e - s}")
del item [c=3, del list[10:]]: 4.600000465870835e-06
del item [c=5, del list[10:]]: 0.0003085000007558847
del item [c=7, del list[10:]]: 0.03811470000073314
del item [c=8, del list[10:]]: 0.36907919999976
del item [c=3, del list[-10:]: 3.4000004234258085e-06
del item [c=5, del list[-10:]: 1.2000000424450263e-06
del item [c=7, del list[-10:]: 3.600000127335079e-06
del item [c=8, del list[-10:]: 1.1600001016631722e-05
from time import perf_counter
C = [3, 5, 7, 8]
for c in C:
l = [0 for _ in range(10**c)]
s = perf_counter()
del l[10]
e = perf_counter()
print(f"del item [c={c}, del list[10]: {e - s}")
print()
for c in C:
l = [0 for _ in range(10**c)]
s = perf_counter()
del l[-10]
e = perf_counter()
print(f"del item [c={c}, del list[-10]: {e - s}")
del item [c=3, del list[10]: 6.999998731771484e-07
del item [c=5, del list[10]: 5.290000081004109e-05
del item [c=7, del list[10]: 0.009698500000013155
del item [c=8, del list[10]: 0.11039209999944433
del item [c=3, del list[-10]: 0.0001799000001483364
del item [c=5, del list[-10]: 8.999995770864189e-07
del item [c=7, del list[-10]: 2.3000011424301192e-06
del item [c=8, del list[-10]: 2.6999987312592566e-06
【Python】Metaclass
https://astropengu.in/posts/32/
- __new__
は初期化されていないクラスのインスタンスを生成するときに使われる
- __init__
はインスタンス生成後に初期化のために呼び出される
つまり__init__
ではインスタンスは生成されない。=>コンストラクタではない
# 下記の2つの生成方法は等価
# 通常のインスタンス生成
obj == Class(arg)
# __new__, __init__を明示的に呼び出す場合
# Classに__new__が定義されていない場合はobject.__new__が呼び出される
obj = Class.__new__(Class, arg)
obj._init_(arg)
type
を使って下記のように動的に生成できる。
def __init__(self, arg):
self.arg = arg
# type(name, base, dict, **kwds) -> new type
Class = type("class_created_by_type", (object,), {"__init__": __init__})
print(Class) # -> <class '__main__.class_created_by_type'>
type
のインスタンスがクラスになっている。
このようにインスタンスがクラスになるようなクラスのことをメタクラスと呼ぶ。
通常のクラス定義ではメタクラスがtype
になっている。つまり暗黙的に下記と等価である。
最終的にはtype
が呼び出されインスタンスが返されればよいので、metaclassに渡すのはcallableなオブジェクトであればクラスでも関数でも構わない。
def add_test_to_method_name(name, bases, dict):
new_dict = {f"{key}_test": val for key, val in dict.items()}
return type(name, bases, new_dict)
class Test(metaclass=add_test_to_method_name):
def print_text(self, txt: str):
print(txt)
t = Test()
t.print_text_test("print_text_test")
t.print_text("print_text")
"""実行結果
print_text_test
Traceback (most recent call last):
File "c:\github\design-pattern\test.py", line 12, in <module>
t.print_text("print_text")
AttributeError: 'Test' object has no attribute 'print_text'
"""
class AddTest(type):
def __new__(cls, *args, **kwds):
print("metaclass: __new__")
d = {f"{key}_test": val for key, val in args[2].items()}
new_args = (args[0], args[1], d)
return super().__new__(cls, *new_args, **kwds)
def __init__(self, *args, **kwds):
print("metaclass: __init__")
return super().__init__(*args, **kwds)
class Test(metaclass=AddTest):
def print_text(self, txt: str):
print(txt)
print("==== start ====")
t = Test()
t.print_text_test("print_text_test")
print("==== end ====")
"""実行結果
metaclass: __new__
metaclass: __init__
==== start ====
print_text_test
==== end ====
"""
【Python】__call__
インスタンス化したオブジェクトを関数のようにobj()
呼び出したときに実行される。
また生成オブジェクトよりメタクラスの__call__
のほうが優先される様子。
from typing import Any
class Test():
def __call__(self, *args: Any, **kwds: Any) -> Any:
print("Test __call__ function")
t = Test()
t() # -> Test __call__ function
from typing import Any
class TestMeta(type):
def __new__(cls, name, bases, dict):
return super().__new__(cls, name, bases, dict)
def __call__(self, *args: Any, **kwds: Any) -> Any:
print("TestMeata __call__ function")
return self
class Test(metaclass=TestMeta):
def __call__(self, *args: Any, **kwds: Any) -> Any:
print("Test __call__ function")
print("テストインスタンス初期化: 開始")
t = Test()
print("テストインスタンス初期化: 終了")
t()
"""実行結果
テストインスタンス初期化: 開始
TestMeata __call__ function
テストインスタンス初期化: 終了
TestMeata __call__ function
"""