2017-11-29 9 views
2

基本的に、メソッドを持つクラスがありますが、そのうちのいくつかはそのカテゴリにラベルを付けることができます。たとえば:特定のクラスメソッドにタグを付ける方法はありますか?

class ExampleClass: 
    # category: foo 
    def method_a(self): 
     """does stuff""" 

    # category: foo 
    def method_b(self): 
     """does stuff""" 

    def method_c(self): 
     """does stuff""" 

    # category: bar 
    def method_d(self): 
     """does stuff""" 

    # category: foo 
    def method_e(self): 
     """does stuff""" 

は今、私はクラスの名前空間に目を通すと、特定のカテゴリで標識されているすべてのメソッドの名前を返します別の関数を書きたいです。 (セイ、例えば、私は特定のタグを持つすべてのメソッドを実行したかったので)

def find_methods(class, label): 
    """Searches through the class namespace 
     returns all methods with the correct label""" 

たとえば、これは望まれる出力です:

find_methods(ExampleClass, 'foo') 
# Returns ['method_a', 'method_b', 'method_e'] 

find_methods(ExampleClass, 'bar') 
# Returns ['method_d'] 

find_methods(ExampleClass, 'baz') 
# Returns [] 

場合、私は思ったんだけどこれを実装する簡単な方法があります。

手動で行うことは、クラスの先頭に定義された変数にメソッド名とカテゴリのリストを維持することですが、新しいメソッドを追加するたびに私のリストを更新してください。また、ExampleClassから継承し、タグも持つクラスがあると、本当に混乱します。

答えて

3

EDIT:より良い解決策は、参照してください以下のセクションで説明します。

必要に応じて、dirのクラスを検索せず、すべてfind_methodsの呼び出しごとに検索することができます。これは、私がタグ付け機能をよりスマートにし、それらを追加して辞書に格納するときにタグ付き機能のリストを構築する場合です。 Find_methodsは辞書から関数リストを取得するだけです。

例えば

class Tagger(object): 
    def __init__(self): 
    self._dict = {} 

    def __call__(self, name): 
    if name not in self._dict: 
     self._dict[name] = [] 
    def tags_decorator(func): 
     self._dict[name].append(func) 
     func._tag = name 
     return func 
    return tags_decorator 

tag = Tagger() 
class ExampleClass: 
    @tag('foo') 
    def method_a(self): 
    """does stuff""" 

    @tag('foo') 
    def method_b(self): 
    """does stuff""" 

    def method_c(self): 
    """does stuff""" 

    @tag('bar') 
    def method_d(self): 
    """does stuff""" 

    @tag('bar') 
    def method_e(self): 
    """does stuff""" 

print(tag._dict) 

ORIGINAL POST:最終溶液の説明。

私は他の誰かから与えられたアイデアを拡張しますが、削除されました。彼はすべての機能のプライベート属性_tagを追加することを提案しました。 Pythonのすべてがオブジェクトなので、これを行うことができます。だから、

class ExampleClass: 
    # category: foo 
    def method_a(self): 
     """does stuff""" 
    method_a._tag = "foo" 

それはしかし汚いコードなので、多分私たちはより良い行うことができますか?例えば。関数でタグ付けすることができます。

def add_foo_tag(func): 
    func._tag = "foo" 
    return func 

class ExampleClass: 
    # category: foo 
    def method_a(self): 
     """does stuff""" 
    method_a = add_foo_tag(method_a) 

しかし、我々はまだ良く行うことができます。

class ExampleClass: 
    # category: foo 
    @add_foo_tag 
    def method_a(self): 
     """does stuff""" 

しかし、どのような他のタグ文字列で:デコレータが私たちのためにmethod_a = add_foo_tag(method_a)を呼ぶであろう、そのため@を構文がありますか?タグデコレータ工場を作ろう!

def tag(tag_name): 
    def tags_decorator(func): 
     func._tag = tag_name 
     return func 
    return tags_decorator 

と構文がいいです。今

class ExampleClass: 
    @tag('foo') 
    def method_a(self): 
     """does stuff""" 

    @tag('foo') 
    def method_b(self): 
     """does stuff""" 

    def method_c(self): 
     """does stuff""" 

    @tag('bar') 
    def method_d(self): 
     """does stuff""" 

    @tag('bar') 
    def method_e(self): 
     """does stuff""" 

、どのようなクラスのメソッドを見つけると?使用できる操作はdirです。コードの明示的なバージョンがあります:

def find_methods_explicit(cls, label): 
    """Searches through the class namespace 
    returns all methods with the correct label""" 
    attributes = [getattr(cls, func) for func in dir(cls)] 
    tagged = [attr for attr in attributes if '_tag' in dir(atrr)] 
    labeled = [attr for attr in tagged if atrr._tag == label] 
    return labeled 

とワンライナー:

def find_methods(cls, label): 
    """Searches through the class namespace 
     returns all methods with the correct label""" 
    return [getattr(cls, func) for func in dir(cls) if '_tag' in dir(getattr(cls, func)) and getattr(cls, func)._tag == label] 

最後に、用法:

print(ExampleClass.method_a._tag)  
print(find_methods(ExampleClass,'foo')) 
print(find_methods(ExampleClass,'bar')) 
print(find_methods(ExampleClass,'qwe')) 

全コード:

def tag(tag_name): 
    def tags_decorator(func): 
     func._tag = tag_name 
     return func 
    return tags_decorator 

class ExampleClass: 
    @tag('foo') 
    def method_a(self): 
     """does stuff""" 

    @tag('foo') 
    def method_b(self): 
     """does stuff""" 

    def method_c(self): 
     """does stuff""" 

    @tag('bar') 
    def method_d(self): 
     """does stuff""" 

    @tag('bar') 
    def method_e(self): 
     """does stuff""" 

def find_methods(cls, label): 
    """Searches through the class namespace 
     returns all methods with the correct label""" 
    return [getattr(cls, func) for func in dir(cls) if '_tag' in dir(getattr(cls, func)) and getattr(cls, func)._tag == label] 

print(ExampleClass.method_a._tag) 

print(find_methods(ExampleClass,'foo')) 
print(find_methods(ExampleClass,'bar')) 
print(find_methods(ExampleClass,'qwe')) 

とオンライン例:https://repl.it/repls/FrayedMilkyKangaroo

0
for method_name in dir(ExampleClass): 
    if callable(getattr(ExampleClass, method_name)): 
     print(method_name) 

機能で編集

、これがあろう。

def find_methods(classobj, label): 
    for method_name in dir(classobj): 
     if method_name == label: 
      if callable(getattr(classobj, method_name)): 
       print(method_name)   
+0

この関数は、メソッド名が特定の名前と等しいかどうかをチェックします。私が気にするのは、メソッド名に特定の名前のタグが付いているかどうかです。メソッド名自体は何でもかまいません。 –

+0

タグはどのくらいの頻度で変更されますか? @ K.Mao – Philip556677

+0

非常にまれです。前にも述べたように、メソッドとタグをマップする変数をクラスの先頭に含めることができます。しかし、これは維持するのがより難しく、ExampleClassを継承し、子クラスに追加のタグを持っていると、特に面倒です。 –

0

あなたは(誤って)型注釈を使用することができます。

def f(args) -> "category": 
    # code 

f_category = f.__annotations__.get('return') # None if no category defined 

それとも機能を使用することができます属性:

def f(args): 
    # code 

f.category = "category" 

f_category = f.category 

そしてfind_methods用:

def find_methods(class, label): 
    for name in dir(class): 
     possible_method = getattr(class, name) 
     # test if it has the right label and is a function 
     yield name # or append to a list and return 
+0

私はそれを使いこなす必要がありますが、私は関数の属性が私が探しているものの線に沿っていると仮定します –

+0

あなたがそれをしたいと思えば、私はもう一つの答えを見るでしょう、それはこれよりも詳細に入ります。 –

関連する問題