こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Python3でのメタプログラミングについて

下記の Ruby スクリプトと同じことを Python で行う場合、どのように実装すればいいでしょうか?
<前提>
・メソッドを Klass クラスに実行時に動的に追加する。
・追加したメソッドの動的削除、変更は必要ない。
・メソッド定義は、Python のオブジェクトではなく単なる文字列。
・メソッド内部から Klass クラス内のインスタンス変数にアクセスする。
・Klass クラスや Klass インスタンスを扱う処理から、動的に追加したメソッドを呼び出す。
・追加したメソッドはシングルトンメソッドである必要はない。
<目的>
Klass クラスのカスタマイズ機能をメソッド定義文として外部に保存しておいて、実行時に呼び出して機能を拡張するような目的です。Klass クラスはめったに変更されないもの、カスタマイズ機能(メソッド定義文)はよく変更されるもの、という切り分けをしたいため、単純に多重継承や MixIn はしたくないです。(上手い方法があればいいのですが…)

#!/usr/bin/env ruby
# coding: utf-8

# 文字列のメソッド定義
$user_funcs = ['
def user_foo()
puts "foo" * @x
end
',
'
def user_bar()
puts "bar" * @x
end
']
# ↑本来は文字列として外部DBに記録されている。

# ----

#
# 拡張したいクラス
#
class Klass

# インスタンス変数を持つ
def initialize
@x = 3
end
attr_accessor :x

# 文字列で定義されたメソッドを追加
$user_funcs.each do |f|
eval f
end
end

# ----

#
# 呼出方法
#

obj = Klass.new
# 追加されたメソッド(user_から始まる名前)を列挙しながら実行する
# => どんな定義がされていても、命名規則さえ守っていれば呼び出し側はそのメソッド名を知る必要はない。
obj.methods.select {|m| /^user_/ =~ m }.each do |m|
eval "obj.#{m}"
end

# 追加されたメソッドはシングルトンメソッドではなく、あくまでもインスタンスメソッドである。
obj2 = Klass.new

# インスタンス変数の書き換え
obj2.x = 4

# インスタンスメソッドの書き換え
def obj2.user_bar()
puts "hoge" * @x
end

obj2.methods.select {|m| /^user_/ =~ m }.each do |m|
eval "obj2.#{m}"
end

投稿日時 - 2019-03-28 14:19:56

QNo.9601308

すぐに回答ほしいです

質問者が選んだベストアンサー

どうでしょう。
https://pastebin.com/yWt6akGy

投稿日時 - 2019-04-02 23:03:42

お礼

ありがとうございました。

投稿日時 - 2019-04-23 00:08:42

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問