"""
tkobjectモジュール
このモジュールは、汎用的なユーティリティ機能を提供する基底クラス`tkObject`を定義します。
属性の操作、デバッグ出力、クラス情報の取得など、オブジェクト指向プログラミングにおける共通の機能を提供します。
関連リンク: :doc:`tkobject_usage`
"""
from pprint import pprint
import re
def _analyze_varstr(str):
"""
概要: 文字列から変数名とインデックス(またはキー)を解析します。
詳細説明:
入力文字列が `varname[index]` または `varname(key)` の形式である場合、
変数名とそのインデックスまたはキーを抽出します。
インデックスは整数に変換を試み、失敗した場合は文字列として扱われます。
上記の形式に一致しない場合は、入力文字列全体を変数名として返し、インデックスはNoneとします。
:param str: 解析対象の文字列。例: "my_list[0]", "my_dict['key']", "simple_var"
:type str: str
:returns: 変数名と、インデックスまたはキーのタプル。インデックスがない場合は(str, None)を返します。
:rtype: tuple[str, int | str | None]
"""
match = re.match(r'^(\S+)(\[|\()(.+)(\]|\))$', str)
if match is None:
return str, None
varname = match.group(1)
index = match.group(3)
# print("varname=", varname, index)
try:
n = int(index)
return varname, n
except:
# print("index=[{}]".format(index))
s = index.strip('"')
s = s.strip("'")
return varname, s
[ドキュメント]
class tkObject:
"""
概要: 汎用的なユーティリティ機能を提供する基底クラスです。
詳細説明:
このクラスは、Pythonオブジェクトに共通して必要とされる様々なヘルパーメソッドを提供します。
属性の取得/設定、メソッドの実行、クラスメンバーのリスト化、デバッグ出力などが含まれます。
他のクラスはこのtkObjectを継承することで、これらのユーティリティ機能を簡単に利用できます。
:ivar debug: デバッグ出力のレベルを設定します。この値以上のレベルの`dprint`や`dpprint`が実行されます。
:vartype debug: int
:ivar debug_explicit: 厳密なデバッグモードを設定します。(現在は未使用)
:vartype debug_explicit: int
"""
debug = 0
debug_explicit = 0
# def __ini__(self, **args):
# self.update(**args)
def __del__(self):
"""
概要: オブジェクトが破棄される際に呼び出されるデストラクタです。
詳細説明:
このメソッドは現在のところ何も処理を行いません。
"""
pass
def __str__(self):
"""
概要: オブジェクトの文字列表現を返します。
詳細説明:
モジュール名とクラス名を結合した形式の文字列を返します。
:returns: オブジェクトの文字列表現。
:rtype: str
"""
return "{}.{}".format(__name__, self.__class__.__name__)
[ドキュメント]
def hasattr(self, attribute):
"""
概要: オブジェクトが指定された属性を持っているかを確認します。
:param attribute: 確認する属性名。
:type attribute: str
:returns: オブジェクトが指定された属性を持っている場合はTrue、そうでない場合はFalse。
:rtype: bool
"""
return hasattr(self, attribute)
[ドキュメント]
def callable(self, method):
"""
概要: 指定されたメソッドが呼び出し可能であるかを確認します。
:param method: 確認するメソッド名。
:type method: str
:returns: 指定されたメソッドが呼び出し可能であればTrue、そうでない場合はFalse。
:rtype: bool
"""
return callable(getattr(self, method))
[ドキュメント]
def exec_method(self, method, *args, **kwarg):
"""
概要: 指定されたメソッドを引数付きで実行します。
詳細説明:
オブジェクト内に指定された名前のメソッドが存在し、それが呼び出し可能であれば、
提供された位置引数とキーワード引数を使用してそのメソッドを実行します。
メソッドが存在しない、または呼び出し可能でない場合は何も行いません。
:param method: 実行するメソッドの名前。
:type method: str
:param args: メソッドに渡す位置引数。
:type args: tuple
:param kwarg: メソッドに渡すキーワード引数。
:type kwarg: dict
:returns: None
:rtype: None
"""
func = getattr(self, method, None)
if func and callable(func):
func(*args, **kwargs)
[ドキュメント]
def get_class(self):
"""
概要: オブジェクトのクラスを返します。
:returns: オブジェクトのクラス。
:rtype: type
"""
return self.__class__
[ドキュメント]
def get_attributes(self):
"""
概要: クラスの全ての属性名(メソッドと変数を含む)のリストを返します。
詳細説明:
`dir(self.__class__)` を使用して、クラスとその基底クラスのすべての属性名を返します。
:returns: 属性名のリスト。
:rtype: list[str]
"""
return dir(self.__class__)
[ドキュメント]
def get_member_functions(self, obj = None):
"""
概要: オブジェクトまたは指定されたオブジェクトのクラスに属する呼び出し可能なメソッド名のリストを返します。
詳細説明:
`obj` が指定されない場合、自身のクラスのメソッドをリストします。
`obj` が指定された場合、そのオブジェクトのクラスのメソッドをリストします。
:param obj: メンバー関数を取得する対象のオブジェクト。指定されない場合は自身のオブジェクト。
:type obj: object | None
:returns: 呼び出し可能なメソッド名のリスト。
:rtype: list[str]
"""
if obj is None:
class_type = self.__class__
else:
class_type = obj.__class__
return [method for method in dir(class_type) if callable(getattr(class_type, method))]
[ドキュメント]
def get_member_variables(self, obj = None):
"""
概要: オブジェクトまたは指定されたオブジェクトのクラスに属する呼び出し可能でない変数名のリストを返します。
詳細説明:
`obj` が指定されない場合、自身のクラスの変数をリストします。
`obj` が指定された場合、そのオブジェクトのクラスの変数をリストします。
クラスレベルの変数を含みます。
:param obj: メンバー変数を取得する対象のオブジェクト。指定されない場合は自身のオブジェクト。
:type obj: object | None
:returns: 呼び出し可能でない変数名のリスト。
:rtype: list[str]
"""
if obj is None:
class_type = self.__class__
else:
class_type = obj.__class__
return [method for method in dir(class_type) if not callable(getattr(class_type, method))]
[ドキュメント]
def get_dict(self):
"""
概要: オブジェクトの `__dict__` を返します。
詳細説明:
インスタンスの属性を格納している辞書を直接返します。
:returns: オブジェクトの `__dict__` 辞書。
:rtype: dict
"""
return self.__dict__
[ドキュメント]
def get_members(self):
"""
概要: クラスのメソッド、変数、およびインスタンス辞書をまとめて返します。
詳細説明:
クラスに定義されている呼び出し可能なメソッドのリスト、呼び出し可能でない変数のリスト、
そしてインスタンスの `__dict__` をタプルとして返します。
:returns: (メソッド名のリスト, 変数名のリスト, インスタンス辞書) のタプル。
:rtype: tuple[list[str], list[str], dict]
"""
class_type = self.__class__
funcs = [method for method in dir(class_type) if callable(getattr(class_type, method))]
vars = [method for method in dir(class_type) if not callable(getattr(class_type, method))]
return funcs, vars, getattr(self, "__dict__", None)
[ドキュメント]
def get(self, key, defval = None):
"""
概要: オブジェクトのインスタンス変数 `__dict__` から指定されたキーの値を返します。
詳細説明:
キーが存在しない場合は `defval` を返します。
:param key: 取得する属性のキー(名前)。
:type key: str
:param defval: キーが存在しない場合に返すデフォルト値。
:type defval: any
:returns: 指定されたキーの値、またはデフォルト値。
:rtype: any
"""
return self.__dict__.get(key, defval)
[ドキュメント]
def set_attribute(self, key, val):
"""
概要: オブジェクトのインスタンス変数 `__dict__` に指定されたキーと値を設定します。
:param key: 設定する属性のキー(名前)。
:type key: str
:param val: 設定する値。
:type val: any
:returns: None
:rtype: None
"""
self.__dict__[key] = val
[ドキュメント]
def get2(self, key, defval = None):
"""
概要: 変数名とインデックス(またはキー)を含む文字列から属性値を取得します。
詳細説明:
`_analyze_varstr` を使用してキーを解析し、`obj.varname[index]` の形式で
アクセスを試みます。例えば、`"my_list[0]"` のようなキーでリストの要素を取得できます。
インデックスが指定されていない場合は、変数名に対応する値をそのまま返します。
:param key: 取得する属性のキー文字列。例: "variable_name", "list_name[index]", "dict_name['key']"
:type key: str
:param defval: キーが存在しない場合に返すデフォルト値。
:type defval: any
:returns: 指定されたキーまたはインデックスに対応する値、またはデフォルト値。
:rtype: any
"""
varname, index = _analyze_varstr(key)
var = self.__dict__.get(varname, defval)
if var is None:
return None
if index is None:
return var
return var[index]
[ドキュメント]
def set_attribute2(self, key, val, assign_dict_element_vars = False):
"""
概要: 変数名とインデックス(またはキー)を含む文字列を使用して属性値を設定します。
詳細説明:
`_analyze_varstr` を使用してキーを解析し、`obj.varname[index] = val` の形式で
値を設定します。例えば、`"my_list[0]"` のようなキーでリストの要素を更新できます。
インデックスが指定されていない場合は、変数名に対応する値を直接設定します。
`assign_dict_element_vars` がTrueの場合、解析前のキーもそのまま辞書に設定されます。
:param key: 設定する属性のキー文字列。例: "variable_name", "list_name[index]", "dict_name['key']"
:type key: str
:param val: 設定する値。
:type val: any
:param assign_dict_element_vars: 解析前のキーも辞書に設定するかどうか。
:type assign_dict_element_vars: bool
:returns: None
:rtype: None
"""
varname, index = _analyze_varstr(key)
if index is None:
self.__dict__[key] = val
else:
# if varname in self.__dict__:
# if type(index) is int:
# self.__dict__[varname] = []
# self.__dict__[varname][index] = val
# else:
# self.__dict__[varname] = {}
# self.__dict__[varname][index] = val
self.__dict__[varname][index] = val
if assign_dict_element_vars:
self.__dict__[key] = val
[ドキュメント]
def update(self, check_defined = False, **kwargs):
"""
概要: キーワード引数を使用してオブジェクトの属性を一括更新します。
詳細説明:
提供されたキーワード引数のキーと値のペアを、オブジェクトの属性として設定します。
`check_defined` がTrueの場合、既存の属性として定義されていないキーが `kwargs` に含まれていると、
エラーメッセージを出力し、プログラムを終了します。
:param check_defined: 未定義のキーが含まれている場合にエラーを発生させるかどうか。
:type check_defined: bool
:param kwargs: 更新する属性名と値のペア。
:type kwargs: dict
:returns: None
:rtype: None
"""
errors = []
for key, val in kwargs.items():
if check_defined and key not in self.__dict__.keys(): # 修正: self.keys() -> self.__dict__.keys()
errors.append(f"key {key} is not defined")
else:
setattr(self, key, val)
if len(errors) > 0:
print("Error(s) in {}.{}:".format(__name__, self.__class__.__name__))
for err in errors:
print(" {}".format(err))
print("")
exit()
'''
if self.debug_explicit == 1:
errors = []
for key in kwargs.keys():
if not key in self.keys():
errors.append("key {} is not defined".format(key))
if len(errors) > 0:
print("Error(s) in {}.{}:".format(__name__, self.__class__.__name__))
for err in errors:
print(" {}".format(err))
print("")
exit()
# setattr(self, key, args[key])
print("kwargs=", kwargs)
self.__dict__.update(kwargs)
'''
[ドキュメント]
def print_attributes(self, print_header = 1):
"""
概要: オブジェクトの全てのインスタンス属性とその値をコンソールに出力します。
詳細説明:
`self.__dict__` に格納されている全てのキーと値のペアを整形して出力します。
`print_header` が1の場合、クラス名を含むヘッダー行が出力されます。
:param print_header: ヘッダーを出力するかどうか (1: 出力, 0: 出力しない)。
:type print_header: int
:returns: None
:rtype: None
"""
keys = self.__dict__.keys()
if print_header:
print("attributes in {}".format(self.ClassPath()))
for key in keys:
print(" {}: {}".format(key, self.__dict__[key]))
[ドキュメント]
def debugprint(self, level, *args):
"""
概要: 指定されたデバッグレベルでメッセージを出力します。(dprintのエイリアス)
詳細説明:
オブジェクトの `debug` レベルが指定された `level` 以上の場合にのみ、
引数 `args` をそのまま `print` 関数に渡して出力します。
:param level: メッセージを出力するためのデバッグレベル。
:type level: int
:param args: 出力するメッセージの可変引数。
:type args: tuple
:returns: None
:rtype: None
"""
self.dprint(level, *args)
[ドキュメント]
def dprint(self, level, *args):
"""
概要: 指定されたデバッグレベルでメッセージを出力します。
詳細説明:
オブジェクトの `debug` レベルが指定された `level` 以上の場合にのみ、
引数 `args` をそのまま `print` 関数に渡して出力します。
:param level: メッセージを出力するためのデバッグレベル。
:type level: int
:param args: 出力するメッセージの可変引数。
:type args: tuple
:returns: None
:rtype: None
"""
if self.debug >= level:
print(*args)
[ドキュメント]
def debugpprint(self, level, *args):
"""
概要: 指定されたデバッグレベルでpretty-printを使用してメッセージを出力します。(dpprintのエイリアス)
詳細説明:
オブジェクトの `debug` レベルが指定された `level` 以上の場合にのみ、
引数 `args` をそのまま `pprint` 関数に渡して出力します。複雑なデータ構造のデバッグに適しています。
:param level: メッセージを出力するためのデバッグレベル。
:type level: int
:param args: 出力するメッセージの可変引数。
:type args: tuple
:returns: None
:rtype: None
"""
self.dpprint(level, *args)
[ドキュメント]
def dpprint(self, level, *args):
"""
概要: 指定されたデバッグレベルでpretty-printを使用してメッセージを出力します。
詳細説明:
オブジェクトの `debug` レベルが指定された `level` 以上の場合にのみ、
引数 `args` をそのまま `pprint` 関数に渡して出力します。複雑なデータ構造のデバッグに適しています。
:param level: メッセージを出力するためのデバッグレベル。
:type level: int
:param args: 出力するメッセージの可変引数。
:type args: tuple
:returns: None
:rtype: None
"""
if self.debug >= level:
pprint(*args)
[ドキュメント]
def IfYes(self, condition, vartrue, varfalse):
"""
概要: 条件に基づいて2つの値のいずれかを返します。
詳細説明:
`condition` が真と評価される場合は `vartrue` を返し、
そうでない場合は `varfalse` を返します。三項演算子の代替として使用できます。
:param condition: 評価する条件。
:type condition: bool
:param vartrue: 条件が真の場合に返す値。
:type vartrue: any
:param varfalse: 条件が偽の場合に返す値。
:type varfalse: any
:returns: 条件が真であれば`vartrue`、偽であれば`varfalse`。
:rtype: any
"""
if condition:
return vartrue
else:
return varfalse
[ドキュメント]
def errormsg(self, funcname, str):
"""
概要: エラーメッセージを標準出力に表示します。
詳細説明:
モジュール名、クラス名、関数名、および提供されたエラー文字列を含む
フォーマットされたエラーメッセージを出力します。
:param funcname: エラーが発生した関数名。
:type funcname: str
:param str: エラーの詳細を示すメッセージ。
:type str: str
:returns: None
:rtype: None
"""
print("Error in {}.{}: {}".format(self.ClassPath(), funcname, str))
[ドキュメント]
def ModuleName(self):
"""
概要: オブジェクトが属するモジュール名を返します。
:returns: 現在のモジュール名。
:rtype: str
"""
return __name__
[ドキュメント]
def ClassName(self):
"""
概要: オブジェクトのクラス名を返します。
:returns: オブジェクトのクラス名。
:rtype: str
"""
return self.__class__.__name__
[ドキュメント]
def FunctionName(self):
"""
概要: 現在実行中の関数の名前を返します。
詳細説明:
このメソッドは、`sys` モジュールがインポートされていることを前提としています。
呼び出し元の関数名を動的に取得するために使用されます。
(既存のコードに`import sys`がありません。実行するとNameErrorが発生します。)
:returns: 現在の関数名。
:rtype: str
"""
import sys # この行は既存コードの一部ではなく、説明のためのコメントです。実際にはモジュールトップレベルでのimportが必要です。
return sys._getframe().f_code.co_name
#import inspect
# f = inspect.currentframe()
# return inspect.getframeinfo(f)[2]
[ドキュメント]
def ClassPath(self):
"""
概要: モジュール名とクラス名を結合したフルパスを返します。
詳細説明:
`ModuleName()` と `ClassName()` メソッドの結果を結合し、
`"モジュール名.クラス名"` の形式の文字列を生成します。
:returns: モジュール名とクラス名を結合した文字列。
:rtype: str
"""
return self.ModuleName() + '.' + self.ClassName()