1

具体的には、タイプのユーザー定義クラスがあります

class Foo(object):
  def __init__(self, bar):
    self.bar = bar

  def bind(self):
    val = self.bar
    do_something(val)

する必要がある:

1) クラス (クラスのインスタンスではない) を呼び出して、クラスself.xxx内で定義されたすべての属性を回復できる。

クラスのインスタンスの場合、これは a を実行してから を実行することで実行できf = Foo('')ますf.__dict__。インスタンスではなく、クラスに対してそれを行う方法はありますか? はいの場合、どのように?Foo.__dict__私は戻ってくることを期待し{'bar': None}ていますが、このようには機能しません。

self.xxx2)クラスの特定の関数から呼び出されるすべてのパラメーターにアクセスできる。たとえば、私はやりたいしFoo.bind.__selfparams__、見返りに受け取りたい['bar']です。これを行う方法はありますか?

4

3 に答える 3

3

これは、あなたがやろうとしていることを正しく理解していると仮定すると、動的言語では非常に難しいことです。基本的に、これは、クラスに存在するすべてのインスタンスを調べてから、それらのインスタンスに設定されているすべての属性を収集することを意味します。不可能ではありませんが、デザインとパフォーマンスの両方の観点から、このようなアプローチの実用性に疑問を投げかけます.

より具体的には、「クラス内で定義されたすべての self.xxx 属性」について話していますが、これらはまったく定義されておらず、少なくとも 1 つの場所では定義されていません。クラスに命が吹き込まれます。ここで、すべてのインスタンスが異なる属性を設定していると言っているわけではありませんが、それらは可能性があり、信頼できる汎用ソリューションを得るためには、インスタンスが自分自身に対して行った可能性のあることを文字通り追跡する必要があります. したがって、静的分析アプローチを念頭に置いていない限り、それを達成するためのクリーンで効率的な方法はわかりません(実際、静的分析でさえ、動的言語で一般的に言えば役に立ちません)。

私の主張を証明する簡単な例:

class Foo(object):
    def __init__(self):
        # statically analysable
        self.bla = 3

        # still, but more difficult
        if SOME_CONSTANT > 123:
            self.x = 123
        else:
            self.y = 321

    def do_something(self):
        import random
        setattr(self, "attr%s" % random.randint(1, 100), "hello, world of dynamic languages!")

    foo = Foo()
    foo2 = Foo()
    # only `bla`, `x`, and `y` attrs in existence so far
    foo2.do_something()
    # now there's an attribute with a random name out there
    # in order to detect it, we'd have to get all instances of Foo existence at the moment, and individually inspect every attribute on them.

また、存在するすべてのインスタンスを反復したとしても、すべての可能な属性ではなく、関心のあるもののスナップショットを取得するだけです。

于 2013-09-25T12:46:40.767 に答える
2
  1. これは不可能です。クラスにはこれらの属性はなくそれらを設定する関数だけがあります。したがって、取得するものは何もなく、これは不可能です。

  2. これは、詳細な AST インスペクションでのみ可能です。Foo.bar.func_codeには通常、必要な属性がありますが、 で属性を検索co_freevarsしているselfため、自由変数ではありません。バイトコードを AST に逆コンパイルしてから、そのfunc_code.co_codeAST を歩く必要があります。

これは悪い考えです。何をするにしても、別の方法を見つけてください。

于 2013-09-25T12:51:36.567 に答える
0

これを行うには、クラスのすべてのインスタンスを見つける何らかの方法が必要です。これを行う 1 つの方法は、クラス自体にそのインスタンスを追跡させることです。残念ながら、クラス内のすべてのインスタンスへの参照を保持するということは、それらのインスタンスがガベージ コレクションされないことを意味します。幸いなことに、Python には がweakrefあり、オブジェクトへの参照は保持されますが、Python のメモリ管理への参照としてカウントされないため、通常どおりインスタンスをガベージ コレクションできます。

インスタンスのリストを更新するのに適した場所は、__init__()メソッド内です。__new__()関心の分離が少しきれいであることがわかった場合は、それを行うこともできます。

import weakref

class Foo(object):

    _instances = []

    def __init__(self, value):
        self.value = value

        cls = type(self)
        type(self)._instances.append(weakref.ref(self, 
                                                 type(self)._instances.remove))

    @classmethod
    def iterinstances(cls):
        "Returns an iterator over all instances of the class."
        return (ref() for ref in cls._instances)

    @classmethod
    def iterattrs(cls, attr, default=None):
        "Returns an iterator over a named attribute of all instances of the class."
        return (getattr(ref(), attr, default) for ref in cls._instances)

今、あなたはこれを行うことができます:

f1, f2, f3 = Foo(1), Foo(2), Foo(3)

for v in Foo.iterattrs("value"):
    print v,   # prints 1 2 3

記録として、私はこれが一般的に悪い考えである、および/または実際にはあなたが望んでいるものではないと考える人々と一緒です. 特に、インスタンスは、渡す場所やコードがインスタンスに対して行う処理によっては、予想よりも長く存続する可能性があるため、常にあると思うインスタンスがあるとは限りません。(これの一部は暗黙的に発生することさえあります。) 一般に、これについて明示する方が適切です。クラスのさまざまなインスタンスをコード (およびライブラリ) 全体でランダム変数に格納するよりも、それらのプライマリ リポジトリをリストにします。または他のコンテナにアクセスし、そこからそれらにアクセスします。次に、それらを簡単に反復処理して、必要な属性を取得できます。ただし、このようなユースケースがあるかもしれませんし、コード化することも可能です。

于 2013-09-25T16:09:22.507 に答える