def
define
to say or explain what the meaning of a word or phrase is
https://www.oxfordlearnersdictionaries.com/definition/english/define?q=define
ChatGPT
pythonのdefに関するソースコードはどこにありますか。
Pythonの def は関数を定義するための**文法(構文)**なので、標準ライブラリのように「ソースコードファイル」として存在するわけではありません。def 自体はPythonインタプリタの一部として処理されます。
具体的には:
CPython(標準Python実装)の場合
def の処理は C言語 で書かれている CPython 本体にあります。
関数オブジェクトの生成や呼び出しは主に以下で定義されています:
Python/ceval.c:関数呼び出しやバイトコード実行
Objects/functionobject.c:関数オブジェクトの生成
解析・構文解析は Parser や Grammar に基づきます。
Parser → Python/graminit.c, Python/Parser
字句解析 → Python/ast.c
Pythonレベルで確認できる部分
def で作られるのは functionオブジェクト です。
def foo(x):
return x + 1
print(type(foo)) #
これ自体は Objects/functionobject.c で実装されています。
ソースコードの取得方法
CPythonのGitHubリポジトリ:
https://github.com/python/cpython
関数オブジェクト関連:
Objects/functionobject.c
関数呼び出し・評価:
Python/ceval.c
要するに、def の動作はPythonの文法解析とCで書かれた関数オブジェクトの実装に依存しており、Pythonの「ライブラリの関数」としてのソースは存在しません。
もし希望であれば、def が Python の AST(抽象構文木)にどのように変換され、実行されるか を Python で追跡する例も作れます。
作ってほしいですか?
はい。
では、Pythonで def がどのように AST(抽象構文木) に変換され、どのように関数オブジェクトとして生成されるかを追跡する簡単な例を示します。
import ast
import inspect
# 1. サンプル関数を定義
def foo(x):
return x + 1
# 2. 関数のソースコードを取得
source = inspect.getsource(foo)
print("=== ソースコード ===")
print(source)
# 3. ソースコードをASTに変換
tree = ast.parse(source)
print("\n=== AST構造 ===")
print(ast.dump(tree, indent=4))
# 4. ASTから関数名や引数を確認
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
print(f"\n関数名: {node.name}")
print("引数:", [arg.arg for arg in node.args.args])
print("関数内部の文:")
for stmt in node.body:
print(" ", ast.dump(stmt))
実行例(出力の一部イメージ)
=== ソースコード ===
def foo(x):
return x + 1
=== AST構造 ===
Module(
body=[
FunctionDef(
name='foo',
args=arguments(
posonlyargs=[],
args=[arg(arg='x')],
...
),
body=[
Return(
value=BinOp(
left=Name(id='x'),
op=Add(),
right=Constant(value=1)
)
)
]
)
]
)
関数名: foo
引数: ['x']
関数内部の文:
Return(value=BinOp(left=Name(id='x'), op=Add(), right=Constant(value=1)))
ポイント
def はまず ASTの FunctionDef ノード に変換されます。
ASTからさらにコンパイルされて コードオブジェクト が作られます。
コードオブジェクトをもとに functionオブジェクト が生成され、Pythonで呼び出し可能になります。
もし希望なら、次のステップとして ASTから関数オブジェクトを自作で生成して実行する例 も作れます。
作りますか?
はい。
では、def を使わずに AST から関数オブジェクトを自作で生成して実行する例 を示します。これにより、def が裏で何をしているかを体験できます。
import ast
# 1. 関数のASTを自作
# def foo(x):
# return x + 1
func_ast = ast.FunctionDef(
name='foo',
args=ast.arguments(
posonlyargs=[],
args=[ast.arg(arg='x')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]
),
body=[
ast.Return(
value=ast.BinOp(
left=ast.Name(id='x', ctx=ast.Load()),
op=ast.Add(),
right=ast.Constant(value=1)
)
)
],
decorator_list=[]
)
# 2. ASTをModuleにラップしてコンパイル可能に
module_ast = ast.Module(body=[func_ast], type_ignores=[])
# 3. ASTをコードオブジェクトにコンパイル
compiled_code = compile(module_ast, filename="<ast>", mode="exec")
# 4. 新しい名前空間で実行
namespace = {}
exec(compiled_code, namespace)
# 5. 関数オブジェクトを取得して実行
foo_func = namespace['foo']
print(foo_func(10)) # 出力: 11
ポイント解説
AST生成
FunctionDef ノードで関数名、引数、返り値を定義
ここで x + 1 の式も AST ノード BinOp として定義
Moduleにラップ
compile() でコードオブジェクトに変換するには、必ずモジュール単位である必要があります
コンパイルと実行
compile() で AST → コードオブジェクト
exec() で名前空間に関数を生成
関数オブジェクトの取得
namespace['foo'] が Python の function オブジェクト
これで普通に呼び出し可能
💡 つまり、def 文は 「ASTを作ってコンパイルし、関数オブジェクトを生成して名前空間に登録する」 という一連の処理を1行で行っているイメージです。
希望であれば、次のステップとして ASTを書き換えて動的に関数を変更する例 も作れます。
作りますか?
はい。
では、先ほど作った関数を ASTを書き換えて動的に変更する例 を示します。
これにより、実行中に関数の振る舞いを変えることができます。
import ast
# 元の関数 AST
# def foo(x):
# return x + 1
func_ast = ast.FunctionDef(
name='foo',
args=ast.arguments(
posonlyargs=[],
args=[ast.arg(arg='x')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]
),
body=[
ast.Return(
value=ast.BinOp(
left=ast.Name(id='x', ctx=ast.Load()),
op=ast.Add(),
right=ast.Constant(value=1)
)
)
],
decorator_list=[]
)
# Module にラップ
module_ast = ast.Module(body=[func_ast], type_ignores=[])
# --- ASTを書き換え ---
# 足し算を掛け算に変更
for node in ast.walk(module_ast):
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
node.op = ast.Mult() # + → *
# コンパイルして実行
compiled_code = compile(module_ast, filename="<ast>", mode="exec")
namespace = {}
exec(compiled_code, namespace)
# 関数呼び出し
foo_func = namespace['foo']
print(foo_func(10)) # 出力: 10 * 1 = 10 → 10
print(foo_func(5)) # 出力: 5 * 1 = 5 → 5
ポイント
ast.walk() で AST 内の全ノードを探索
BinOp(二項演算)の演算子を Add → Mult に置換
compile() → exec() で新しい関数オブジェクトが作られる
元の関数定義は書き換えられ、呼び出し時の動作が変わる
💡 このテクニックを応用すると、実行時に関数を自動生成・改変・最適化 することができます。
たとえば数式ジェネレータやコード変換ツールに使われます。
希望であれば、さらに 元の関数を AST に変換 → 自動で演算子だけ変更して新しい関数を生成 という「関数の自動改変パイプライン」の例も作れます。
作りますか?
はい。
では、元の関数を AST に変換して、演算子だけ自動で変更し、新しい関数を生成するパイプライン の例を示します。
import ast
import inspect
import copy
# 元の関数を定義
def foo(x):
return x + 2
# 1. 関数を文字列で取得
source = inspect.getsource(foo)
# 2. ソースコードを AST に変換
tree = ast.parse(source)
# 3. ASTを書き換える関数
def replace_operator(ast_tree, old_op, new_op):
"""
AST内のold_opをnew_opに置換
"""
tree_copy = copy.deepcopy(ast_tree) # 元のASTを保持
for node in ast.walk(tree_copy):
if isinstance(node, ast.BinOp) and isinstance(node.op, old_op):
node.op = new_op()
return tree_copy
# 例: 足し算(+)を掛け算(*)に変更
new_tree = replace_operator(tree, ast.Add, ast.Mult)
# 4. 新しい AST をコンパイル
compiled_code = compile(new_tree, filename="<ast>", mode="exec")
# 5. 新しい関数オブジェクトを作成
namespace = {}
exec(compiled_code, namespace)
new_foo = namespace['foo']
# 6. 動作確認
print("元の関数 foo(3) =", foo(3)) # 出力: 5
print("新しい関数 new_foo(3) =", new_foo(3)) # 出力: 6
ポイント
inspect.getsource() で元の関数を文字列として取得
ast.parse() で AST に変換
ast.walk() で全ノードを探索し、演算子だけ置換
copy.deepcopy() で元の関数 AST を壊さずに保持
compile() + exec() で新しい関数オブジェクトを作成
💡 この方法により、元の関数を変更せずに、任意のルールで関数の動作を改変した新しい関数 を生成できます。
希望であれば、さらに 複数の演算子を自動で置換して、元の関数から派生関数を一括生成するサンプル も作れます。
作りますか?
では、複数の演算子を自動で置換して、元の関数から派生関数を一括生成する例 を示します。
import ast
import inspect
import copy
元の関数を定義
def foo(x, y):
return x + y - 2
1. 関数を文字列で取得
source = inspect.getsource(foo)
2. ソースコードを AST に変換
tree = ast.parse(source)
3. ASTを書き換える関数
def replace_operators(ast_tree, replacements):
"""
AST内の演算子をまとめて置換
replacements: {元の演算子クラス: 新しい演算子クラス}
"""
tree_copy = copy.deepcopy(ast_tree)
for node in ast.walk(tree_copy):
if isinstance(node, ast.BinOp):
for old_op, new_op in replacements.items():
if isinstance(node.op, old_op):
node.op = new_op()
return tree_copy
4. 置換パターンを定義
patterns = [
{ast.Add: ast.Mult}, # + → *
{ast.Sub: ast.Add}, # - → +
{ast.Add: ast.Sub, ast.Sub: ast.Mult}, # 複合置換
]
5. 派生関数を生成
derived_funcs = {}
for i, pattern in enumerate(patterns, start=1):
new_tree = replace_operators(tree, pattern)
compiled_code = compile(new_tree, filename=f"", mode="exec")
namespace = {}
exec(compiled_code, namespace)
derived_funcs[f'foo_variant_{i}'] = namespace['foo']
6. 動作確認
print("元の関数 foo(5, 3) =", foo(5, 3))
for name, func in derived_funcs.items():
print(f"{name}(5, 3) =", func(5, 3))
実行例(出力イメージ)
元の関数 foo(5, 3) = 6
foo_variant_1(5, 3) = 15 # + → * : 53 - 2 = 15-2=13
foo_variant_2(5, 3) = 6 # - → + : 5 + 3 + 2 = 10
foo_variant_3(5, 3) = 15 # +→- , -→ : 5-3*2=5-6=-1
ポイント
演算子置換パターンを複数定義して、一括で派生関数を生成
元の関数は一切変更せず、新しい関数オブジェクトを別名で保持
ASTと compile() + exec() によって動的に関数生成可能
💡 応用例:
数学関数の最適化や変換
コード自動生成ツール
動的に動作を切り替えるプログラム
希望であれば、次のステップとして 任意の関数を自動解析してすべての二項演算子の組み合わせで派生関数を生成する完全自動化例 も作れます。
作りますか?
はい。
では、任意の関数を自動解析して、すべての二項演算子の組み合わせで派生関数を生成する完全自動化例 を作ります。
これにより、元の関数の演算子をすべて網羅的に置換して新しい関数を生成できます。
import ast
import inspect
import copy
import itertools
元の関数
def foo(a, b, c):
return a + b - c
1. 関数のソースを取得してASTに変換
source = inspect.getsource(foo)
tree = ast.parse(source)
2. 対象とする二項演算子と置換候補
bin_ops = [ast.Add, ast.Sub, ast.Mult, ast.Div] # 対象演算子
op_symbols = {ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/'}
3. AST内の全二項演算子を抽出
original_ops = []
for node in ast.walk(tree):
if isinstance(node, ast.BinOp):
original_ops.append(type(node.op))
4. 置換パターンの組み合わせを生成
patterns = list(itertools.product(bin_ops, repeat=len(original_ops)))
5. ASTを書き換える関数
def apply_pattern(ast_tree, pattern):
tree_copy = copy.deepcopy(ast_tree)
idx = 0
for node in ast.walk(tree_copy):
if isinstance(node, ast.BinOp):
node.op = patternidx
idx += 1
return tree_copy
6. 派生関数を生成
derived_funcs = {}
for i, pattern in enumerate(patterns, start=1):
new_tree = apply_pattern(tree, pattern)
compiled_code = compile(new_tree, filename=f"", mode="exec")
namespace = {}
exec(compiled_code, namespace)
func_name = f'foo_variant_{i}'
derived_funcs[func_name] = namespace['foo']
7. 動作確認(例として1つだけ)
example_inputs = (2, 3, 1)
print(f"元の関数 foo{example_inputs} =", foo(*example_inputs))
for name, func in list(derived_funcs.items())[:5]: # 最初の5個だけ表示
print(f"{name}{example_inputs} =", func(*example_inputs))
ポイント
元の関数の AST を解析して、すべての BinOp を抽出
置換候補の演算子リストからすべての組み合わせを生成 (itertools.product)
ASTを書き換えて compile → exec により動的に関数生成
完全自動化で、元の関数を変更せずに派生関数を生成
💡 応用例
数学関数のパターン探索や最適化
教育用に「演算子の違いで結果がどう変わるか」を可視化
コード自動生成・テスト自動化
必要であれば、この自動生成をさらに 名前空間や辞書に整理して検索・呼び出しを簡単にするライブラリ化 した例も作れます。
作りますか?
<この項は書きかけです。順次追記します。>
This article is not completed. I will add some words and/or centences in order.
Este artículo no está completo. Agregaré algunas palabras en orden.
Ref.
大規模言語モデル講座 基礎編 2025 Autumn 敗因を勝因に
https://qiita.com/kaizen_nagoya/items/34ffd2b0c47a5f3665d9
MCP入門 〜面倒なことはAIエージェントにやらせよう〜 by からあげ を聞きながら
https://qiita.com/kaizen_nagoya/items/54b648c838fae8d57e38
MCP入門 〜面倒なことはAIエージェントにやらせよう〜 by からあげ を聞きながら、補足と反論 by ChatGPT
https://qiita.com/kaizen_nagoya/items/0939d58d31666562090c
C言語を習得する3つの方法
https://qiita.com/kaizen_nagoya/items/84cab0888c193bba429b
Views上位64記事 20250617現在
https://qiita.com/kaizen_nagoya/items/26dbbd04cf18b7742972
C言語(C++)が必要な人、必要ない人 with ChatGPT
https://qiita.com/kaizen_nagoya/items/a074cb8cd292d8d94bd4
C言語を習得する3つの方法 with ChatGPT
https://qiita.com/kaizen_nagoya/items/4a3518a18fa49f46787f
<この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。>
This article is an individual impression based on my individual experience. It has nothing to do with the organization or business to which I currently belong.
Este artículo es una impresión personal basada en mi experiencia personal. No tiene nada que ver con la organización o empresa a la que pertenezco actualmente.
文書履歴(document history)
ver. 0.01 初稿 20250618
最後までおよみいただきありがとうございました。
いいね 💚、フォローをお願いします。
Thank you very much for reading to the last sentence.
Please press the like icon 💚 and follow me for your happy life.
Muchas gracias por leer hasta la última oración.
Por favor, haz clic en el ícono Me gusta 💚 y sígueme para tener una vida feliz.