質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

2662閲覧

PHPのマジックメソッドのPython版

snowfaller

総合スコア125

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2016/08/21 04:46

編集2016/08/22 07:56

PHPのメソッドに未定義な関数の呼び出しやプロパティの設定・取得が行われた時に、PHPから呼び出してくれる(いわゆるコールバックしてくれるマジックメソッドがあります。

php

1#!/usr/bin/env php 2<?php 3/* 4__call() : 未定義な関数が呼ばれた時に、その関数名と引数が指定されて呼び出されます 5__get() : 未定義なプロパティを取得しようとした時に、そのプロパティ名が指定されて呼び出されます 6__set() : 未定義なプロパティを設定しようとした時に、そのプロパティ名と値が指定されて呼び出されます 7*/ 8class Test { 9 public function __call($functionName, $args) { 10 printf("Undefined function %s() has been called.\n", $functionName); 11 } 12} 13$inst = new Test(); 14$inst->undefinedTestMethod(); 15?>

これらに該当するPythonの関数をご教授下さい。
前にそのコールバック関数を一度実装したのですが、忘れてしまいました。
(コールバックする側の実装ではなく、コールバックされた側の実装を単純にしたいだけです)

「やってほしいことだけを記載した丸投げの質問」との指摘を受けましたが、これ以上どのように質問して良いのか正直分かりません。
→ マジックメソッドの補足を追加してみました。
→ もうちょっと補足を追加してみました。

【後記】
皆様、ご回答ありがとうございました。
DBのConnectionクラスのProxy(代理人)クラスを作成する上で必要でした。
PHPのマジックメソッドやPythonの特殊メソッドを使用すれば、Javaと比べて、(厳格性には欠けます)非常に、お手軽に実装出来ますね。

【後記2】
ご回答頂いた内容をよく確認したところ、phpの__call()では、その延長で本来のメソッドを呼び出すのですが、pythonの__getattr__()はメソッドのオブジェクトを返す必要があるのですね(その後、pythonがそのメソッドを呼び出す)。
先のphpのコードをpythonに焼きなおすと以下の通りになるかと。(双方共に細かいエラー処理は省略)

python

1#!/usr/bin/env python3 2class Test: 3 def dummy(self, *args): 4 None 5 def __getattr__(self, name): 6 print('Undefined function %s() has been called.' % name) 7 return self.dummy 8def main(): 9 inst = Test() 10 inst.undefinedTestMethod() 11if(__name__ == '__main__'):main()

【後記3】
以下をベースに肉付けしていきます。

python

1#!/usr/bin/env python3 2from os.path import basename, splitext 3class Original: 4 def __init__(self): 5 self.testProperty = 'text of testProperty' 6 def testMethod(self, text): 7 print('testMethod() has been called with \'%s\'' % text) 8class Proxy: 9 def __init__(self, moduleName, className): 10 self.orgInst = getattr(__import__(moduleName, fromlist=[className]), className)() 11 def __getattr__(self, name): 12 attr = getattr(self.orgInst, name) 13 if(callable(attr)): 14 print('*redirecting method %s' % name) 15 # メソッドを呼び出す際の処理 16 else: 17 print('*redirecting property %s' % name) 18 # プロパティを取得する際の処理 19 return attr 20def main(): 21 inst = Proxy(splitext(basename(__file__))[0], 'Original') 22 print(inst.testProperty) 23 inst.testMethod('Hello') 24 inst.testMethod2('This invokation will be failed') 25if(__name__ == '__main__'):main()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

__set(PHP)は__setattr__(Python)に単純対応します。

PHPではアクセスの仕方により__get__callを区別できるようですが、Pythonだと__getattr__のみで簡単には区別できません。下記コードではスタックフレームを参照することで、強引に判断しています。

実行結果:http://melpon.org/wandbox/permlink/gcZMAbRe74w3yDsY

Python

1import inspect 2 3class X(object): 4 def __getattr__(self, key): 5 class MethodHook: 6 def __init__(self, key): 7 self.key = key 8 def __call__(self, *args, **kwargs): 9 print('__call: "{}", {}, {}'.format(self.key, args, kwargs)) 10 11 frame = inspect.getframeinfo(inspect.currentframe().f_back) 12 code = ''.join([line for line in frame.code_context]) 13 code = ''.join(code.split()) + ' ' # remove all spaces and append sentinel 14 s = code[code.index(key) + len(key)] 15 if s == '(': 16 return MethodHook(key) 17 else: 18 print('__get: "{}"'.format(key)) 19 return "placeholder" 20 21 def __setattr__(self, name, value): 22 print('__set: "{}", {}'.format(name, value)) 23 24x = X() 25x.undef_method(1, 2, 3, a1="Hello", a2="World") 26x.hoge = 42 27y = x.hoge 28print("y={}".format(y))

投稿2016/08/21 05:55

編集2016/08/21 05:57
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

snowfaller

2016/08/21 11:40

ご回答有り難うございました。 スタックフレームの参照、興味深いですので、今後、勉強していきたいと思います。
guest

0

ベストアンサー

追記

すいません、 __getattr__ とかの事ですね。

class Sample(): def __init__(self): self.__x = 10 def __private(self, x): print(x) def __getattr__(self, name): if name == 'p': print(str(name) + ' is accessed ') else: return lambda *args: None if __name__ == '__main__': s = Sample() s._Sample__private(1) p = s.p print(s._Sample__x) s.q()

setの方は __setattr__ かと。

検索するなら「python 特殊メソッド」とか「python 特殊メソッド 未定義メンバ」あたりですかね。


追記前(php側の関数を勘違いしていた)

実装というか

class Sample(): def __init__(self): self.__x = 10 def __private(self, x): print(x) if __name__ == '__main__': s = Sample() s._Sample__private(1) print(s._Sample__x)

のようにするだけで、「python privateメンバ」など検索すれば出てくると思いますが。

投稿2016/08/21 05:09

編集2016/08/21 05:30
flied_onion

総合スコア2604

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

snowfaller

2016/08/21 05:45

ありがとうございます。当方の質問が言葉足らずだったと反省し、補足を追加してみました。 Pythonでは「特殊メソッド」と言うのですね。getとsetはご提示頂いた内容で対応できそうですね。 あとは、callでしょうか。「特殊メソッド」から調べてみます。
flied_onion

2016/08/21 06:48

callは s.q() のところで __getattr__ で対応してます( "p" 以外なら関数とみなして何もしない lambda返している)よ。関数を返すことになります。 p,qで見づらかったかもしれませんね。
snowfaller

2016/08/21 11:39

ご回答ありがとうございました。ご回答頂いた内容で対応出来そうです。 最初にご回答頂いたことと、段階的に補足追加頂きましてありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問