関数・オブジェクト・リスト/GHPython でジオメトリデザイン
処理に名前をつけてまとめる——それが関数です。リストと辞書を組み合わせれば、複数の要素を生成しながら同時に集計できます。ジオメトリの生成を「部品の組み立て」として書けるようにします。
1関数の定義
関数とは、入力(引数)を受け取り、決まった手順で計算を実行し、 結果(戻り値)を返すルールのことです。
print(), input())def で自分で定義する関数# 関数の定義
def 関数名(引数名1, 引数名2, ...):
処理1
処理2
return 値 # 関数を実行した結果(戻り値)# 二つの数字を足し算した結果を返す関数を定義する
def add_numbers(a, b):
result = a + b
return result # 関数の戻り値を指定する
# 関数を呼び出す
sum_result = add_numbers(5, 3)
print(f"5 + 3 = {sum_result}") # 出力: 5 + 3 = 8ローカル変数とグローバル変数
# global_value はグローバル変数
global_value = 100
def test_global(arg):
# ローカル変数 arg と グローバル変数 global_value の積
return arg * global_value
print(test_global(10)) # 10 * 100デフォルト引数
値が指定されなかったときに使われる既定値を、引数に持たせておけます。
def func1(arg=999):
print(arg)
func1() # 引数を省略するとデフォルト値が使われる
func1(123) # 指定すればそちらが使われる# 資材の金額に宛名を付ける関数を定義する
def material_price(number_of_stone, number_of_plywood, name="上"):
total_stone = number_of_stone * 500
total_plywood = number_of_plywood * 2000
total = total_stone + total_plywood
print(name, "様:石材", number_of_stone, "個と合板", number_of_plywood, "枚で", total, "円です")
# 関数を呼び出す
material_price(10, 20)
material_price(10, 20, "萬屋")床スラブの面積と厚みから体積(m³)を求め、材料費を計算するプログラムを完成させなさい。厚みは mm、面積は m² で与えられます。
# 1m^3 あたりの材料費(円)
UNIT_COST = 14000
def slab_cost(area_m2, thickness_mm):
# thickness_mm を m に変換
thickness_m = ________
# 体積(m^3)= 面積 × 厚み
volume_m3 = ________
return volume_m3 * UNIT_COST
result = round(slab_cost(48.0, 150))
print(result)ヒント
UNIT_COST はグローバル変数なので関数の中からも見えます。レンガと合板の購入金額に宛名を付けるプログラムを完成させなさい。宛名はデフォルト引数にしておき、省略もできるようにします。
brick = ______("レンガは何個買いますか?") # レンガの個数を入力する
number_of_brick = ______(brick) # 文字列を整数値に変換する
plywood = ______("合板は何枚買いますか?") # 合板の枚数を入力する
number_of_plywood = ______(plywood) # 文字列を整数値に変換する
# 資材の金額に宛名を付ける関数を定義する
def material_price(number_of_brick, number_of_plywood, ___ = "上"):
total_brick = number_of_brick * 500
total_plywood = number_of_plywood * 2000
total = total_brick + total_plywood
print(___, "様:レンガ", number_of_brick, "個と合板", number_of_plywood,
"枚で", total, "円です")
material_price(number_of_brick, number_of_plywood) # 宛名を省略
material_price(40, 70, ___) # 宛名を指定ヒント
___ はすべて同じ「宛名を入れる引数の名前」です。最後の 1 つだけは呼び出し側なので、文字列を渡します。2オブジェクトとリスト
オブジェクトとは、Python が操作するいろいろな種類のデータや
プログラムのことです。整数の 7、文字列の "art"、
関数の print() ——これらはすべてオブジェクトです。
ただし >= や while といった実行命令はオブジェクトではありません。
リスト
リストは、決まった順番に並んだ値で構成されるデータです。 インデックス(順番)は 0 から数えることに注意してください。
stations = ["五日市", "新井口", "西広島", "横川", "新白島", "広島"] print(stations) print(stations[0], stations[5]) # インデックスは 0 から数える
values = ['A', 'B', 'C']
print("修正前:", values)
values.insert(0, 999) # 0 番目に挿入
print("修正後:", values)
values[1] = 'D' # 1 番目を置き換え
print("修正後:", values)
del values[0] # 0 番目を削除
print("修正後:", values)辞書
辞書は、キーと値を対応づけるデータです。
「材料名 → 密度」「階名 → 面積」のように、名前で引きたいデータに向いています。
キーが登録されているかどうかは in 演算子で確かめられます。
english_words = {"apple": "りんご", "orange": "みかん", "peach": "もも"}
print(english_words)
print(english_words["apple"])
print("apple" in english_words) # キーがあるか → True資材の辞書を読み込み、それぞれの名前と密度を表示するプログラムを完成させなさい。
materials = {"oak": 700, "cedar": 380, "steel": 7850}
___ name, rho in __________.items(): # in 演算子による反復処理
______(name, rho)ヒント
辞書.items() は「キーと値の組」を順に取り出します。受け取る変数が 2 つ並んでいるのはそのためです。ネスト
ネストとは、ある構造の中に別の構造を組み込むことです。 リストの中のリスト、ループの中のループ、条件文の中の条件文——いずれも設計の集計や 判定でよく使います。
# ネストされたリスト
nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(nested_list[0][1]) # [1,2,3] の [1] → 2
# ネストされたループ
for sublist in nested_list:
for item in sublist:
print(item, end=" ")
print()じゃんけんゲームのプログラムを完成させなさい。ネストされた条件文で勝敗を判定します。
右の「標準入力」に 1(グー)・2(チョキ)・3(パー)のいずれかを書いて実行します。コンピュータの手は毎回ランダムに決まります。
import random
# じゃんけんの手のリスト
rock_paper_scissors = ["グー", "チョキ", "パー"]
# ゲーム開始のメッセージ
______("じゃんけんしましょう")
______("番号を入力してね")
______("1 番・グー 2 番・チョキ 3 番・パー")
# ユーザーの手の入力
number = ______("あなたの手は?")
# ユーザーの手の判定
if number == "1":
user = "グー"
______ number == "2":
user = "チョキ"
______:
user = "パー"
# コンピューターの手の選択
cpu = random.choice(rock_paper_scissors)
# ユーザーとコンピューターの手を表示
______(f"あなたは{user}。向こうは{cpu}。")
# 勝敗の判定と結果の表示
## あなたがグーの場合
if user == "グー":
if cpu == "グー":
print("あいこ!")
elif cpu == "チョキ":
print("あなたの勝ち!")
else:
print("あなたの負け!")
## あなたがチョキの場合(ネストされた条件文)
elif ___________________
## あなたがパーの場合(ネストされた条件文)
else:
_____________________ヒント
3GHPython でジオメトリ設計
関数・リスト・辞書がそろうと、ジオメトリの生成を「部品」に分けて書けるようになります。 1 フロア分をつくる関数、1 部材をつくる関数——それを組み合わせて全体を組み立てるのが、 Grasshopper でいう「コンポーネントを自分でつくる」ことにあたります。
ファサードの階モジュール
窓 1 枚の寸法や余白は辞書 DEFAULT_SPEC にまとめ、
階数ぶんループを回して全体を組み立てます。集計はネスト辞書 report に入れます。
1 フロア分の窓をつくる関数 make_floor() を定義し、階数ぶん呼び出してファサード全体を組み立てます。既定仕様は辞書 DEFAULT_SPEC にまとめ、デフォルト引数で渡します。
import Rhino.Geometry as rg
# グローバル:既定仕様(辞書)
DEFAULT_SPEC = {
"margin_x": 300.0,
"margin_y": 300.0,
"win_w": 900.0,
"win_h": 1200.0
}
def make_floor(floor_index, W, H, Cols, spec=DEFAULT_SPEC):
# 1 フロア分の窓(矩形 Curve のリスト)と、面積合計を返す
# ローカル変数:この関数内だけで使う値
floor_h = H / ________ # Floors で割って 1 フロア高さ
# 窓配置の基準 Y(下からのオフセット)
y0 = floor_index * floor_h + spec["margin_y"]
curves = []
area_sum = 0.0
# 窓のピッチ
pitch = (W - 2 * spec["margin_x"]) / Cols
for j in range(Cols):
# 各窓の中心 X
cx = spec["margin_x"] + pitch * (j + 0.5)
pl = rg.Plane.WorldXY
pl.Origin = rg.Point3d(cx, y0 + spec["win_h"] * 0.5, 0)
# Rectangle3d(plane, xInterval, yInterval)
rect = rg.Rectangle3d(pl,
rg.Interval(-spec["win_w"] * 0.5, spec["win_w"] * 0.5),
rg.Interval(-spec["win_h"] * 0.5, spec["win_h"] * 0.5))
crv = rect.ToNurbsCurve()
curves.append(crv)
area_sum += spec["win_w"] * spec["win_h"]
return curves, area_sum
# ---- メイン ----
windows_all = []
report = {} # ネスト辞書:各階の集計を入れる
total_area = 0.0
for i in range(Floors):
# 関数呼び出し(デフォルト引数で spec を渡さない)
win_crvs, area = make_floor(________, W, H, Cols)
windows_all.extend(win_crvs)
total_area += area
floor_name = "F{}".format(i + 1)
report[floor_name] = {
"count": len(win_crvs),
"area": area
}
a = windows_all
b = report
c = total_areaヒント
2 つめは「いま何階目か」を関数に渡す変数です。
出力タブを開くと
b の集計辞書が読めます。トラスの重量推定
部材 1 本を返す関数を用意しておけば、長さと重量の集計はループの中で自然に書けます。 材料ごとの密度・断面積はグローバル辞書から引くことで、材料を変えた比較が簡単になります。
部材 1 本をつくる関数 member() と、トラス全体を組む関数 make_truss() を組み合わせます。材料の密度と断面積はグローバル辞書 MAT_DB から引きます。
import Rhino.Geometry as rg
# グローバル:材料 DB(密度は仮の相対値、断面積も仮)
MAT_DB = {
"Steel": {"rho": 7.85e-6, "A": 1200.0}, # rho: kg/mm^3 のつもり
"Timber": {"rho": 0.60e-6, "A": 2000.0}
}
def member(p0, p1, mat="Steel"):
"""部材 1 本を作って、(Line, 長さ, 重量) を返す"""
ln = rg.Line(p0, p1)
L = ln.Length # ローカル変数
# グローバル辞書参照(MAT_DB)
rho = MAT_DB[mat]["rho"]
A = MAT_DB[mat]["A"]
w = L * A * rho
return ln, L, w
def make_truss(Span, Height, Panels, mat=________):
lines = []
length_sum = 0.0
weight_sum = 0.0
dx = Span / Panels
# 節点(下弦)
bot = [rg.Point3d(i*dx, 0, 0) for i in range(Panels+1)]
# 節点(上弦:偶数だけ持ち上げる)
top = [rg.Point3d(i*dx, 0, Height if i%2==0 else Height*0.6) for i in range(Panels+1)]
# 下弦・上弦
for i in range(Panels):
for pA, pB in [(bot[i], bot[i+1]), (top[i], top[i+1])]:
ln, L, w = member(pA, pB, mat=mat)
lines.append(ln); length_sum += L; weight_sum += w
# 斜材
for i in range(Panels):
pA = bot[i]
pB = top[i+1] if i%2==0 else top[i]
ln, L, w = member(pA, pB, mat=mat)
lines.append(ln); length_sum += L; weight_sum += w
return lines, length_sum, weight_sum
# ---- メイン ----
all_lines = []
report = {}
total_weight = 0.0
for mat_key in [DefaultMat, "Timber"]:
lines, Lsum, Wsum = make_truss(Span, Height, Panels, mat=mat_key)
all_lines.extend(lines)
total_weight += Wsum
report[mat_key] = {
"lines": lines,
"length": Lsum,
"weight": Wsum
}
a = all_lines
b = report
c = total_weightヒント
make_truss のデフォルト引数です。MAT_DB のキーになっている文字列を書きます。出力タブで
c(総重量)を見ながら Panels を変えてみましょう。4まとめと課題
本日のまとめ
- 関数によって処理をまとめ、名前をつけて呼び出せるようになった。
- リスト・辞書・ネストで、複数の要素とその集計を扱えるようになった。
- これらを組み合わせて、ファサードやトラスを「部品の組み立て」として生成した。
次回までのミニ課題(最終課題の準備)
Colab で、以下の三つの中から一つを選んでプログラムを完成させてください。
- じゃんけんの対戦結果を記録し、勝率・手の偏りなどを自動集計するプログラム
- じゃんけんの CPU がプレイヤーの癖を学んで勝ちにくるプログラム
- じゃんけんのカードゲーム化
参考リンク
5自由制作
本日の学びを踏まえ、穴あきではなく一からコードを書いて提出する課題です。生成AIの助けを借りて構いません。右の演習環境で開いて制作し、完成したら 提出 を押してください。
第13回の学び(関数・リスト・オブジェクト)を踏まえ、部品を関数に分けて組み立てる作品を提出してください。ロフト・押し出し・配置の組み合わせで、自分のテーマを形にしてみましょう。
import Rhino.Geometry as rg import math # 一から書いてみましょう。生成AIに相談しながらで構いません。 # スライダ x, y, z, n が使えます。完成したら「提出」を押してください。 a = None