19

コードベースを分割するために、より小さなネストされた関数に分割したメソッドがあります。

def foo(x,y):
    def do_this(x,y):
        pass
    def do_that(x,y):
        pass
    do_this(x,y)
    do_that(x,y)
    return

ネストされた関数の1つを単独で実行する方法はありますか?例えば:

foo.do_this(x,y)

編集:

pyramid_breakerを使用して構築したWebサーバーでキャッシュをセットアップしようとしています

def getThis(request):
    def invalidate_data(getData,'long_term',search_term):
         region_invalidate(getData,'long_term',search_term)
    @cached_region('long_term')
    def getData(search_term):
         return response
    search_term = request.matchdict['searchterm']
    return getData(search_term)

これは私の理解が正確ではないかもしれないということです:

これを持っている理由は、デコレータがキャッシュキーを作成するために使用する名前空間が、関数と引数から生成されるためです。したがって、リクエスト変数は一意であり、キャッシュは役に立たないため、getThisにデコレータを配置することはできません。そこで、繰り返し可能な引数(search_term)を持つ内部関数を作成しました。

ただし、キャッシュを無効化(つまり更新)するには、無効化関数はスコープが「getData」関数を認識している必要があるため、ネストする必要もあります。したがって、入れ子関数を呼び出す必要があります。あなたの素晴らしい人々はそれが不可能であることを明らかにしたので、誰かが私が別の構造でそれを行う方法を説明することができますか?

4

7 に答える 7

29

私は仮定do_thisし、do_that実際にはの引数に依存していますfoo。そうでなければ、それらを移動してfoo直接呼び出すことができるからです。

クラスとして全体を作り直すことをお勧めします。このようなもの:

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

    def do_this(self):
        pass

    def do_that(self):
        pass

    def __call__(self):
        self.do_this()
        self.do_that()

foo = Foo(x, y)
foo()
foo.do_this()
于 2012-06-22T10:44:23.983 に答える
17

これを行うことはできないと言っているこれらの以前の回答は、もちろん間違っています。これは python です。魔法のコード マジックを使用して、ほとんど何でも実行できます。

foo の関数コードから最初の定数を取り出すことができます。これがdo_this関数になります。次に、このコードを使用して新しい関数を作成できます。

new の詳細についてはhttps://docs.python.org/2/library/new.htmlを、 internal へのアクセス方法の詳細については https://docs.python.org/2/library/inspect.html を参照してください。コード。

警告: これを行うことができるからといって、これを行う必要があるわけではありません。関数を構造化する方法を再考することが最善の方法ですが、将来おそらく壊れる可能性のある迅速で汚いハックが必要な場合は、次のようにします。

import new
myfoo = new.function(foo.func_code.co_consts[1],{}) 
myfoo(x,y) # hooray we have a new function that does what I want

foo.__code__更新: python3 では、types モジュールを次のように使用できます。

import types
myfoo = types.FunctionType(foo.__code__.co_consts[1], {})
myfoo()  # behaves like it is do_this()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: do_this() missing 2 required positional arguments: 'x' and 'y'
于 2015-10-15T15:09:36.197 に答える
4

ありますが、関数オブジェクトの属性として作成する必要があります。ただし、これは の最初の呼び出し後にのみ機能しfooます。

def foo(x,y):
    def do_this(x,y):
        pass
    def do_that(x,y):
        pass
    do_this(x,y)
    do_that(x,y)
    foo.do_this = do_this
    foo.do_that = do_that
    return

>>> foo.do_this(1, 2)
AttributeError: 'function' object has no attribute 'do_this'
>>> foo(1, 2)
>>> foo.do_this(1, 2)
>>>
于 2012-06-22T10:52:45.993 に答える
3

いいえ(ここでは完全にやり過ぎであるクロージャーオブジェクトを突っついていることは別として)。それが必要な場合は、クラスを使用してください。

class foo(object):
    def do_this(self, x, y):
       ...
    def do_that(self, x, y):
       ...
    def do_other_stuff(self, x, y):
       # or __call__, possibly

または、とにかくすべてを引数として渡すので、これらの関数を外側のスコープに配置します。

def foo(x, y):
    do_this(x, y)
    do_that(x, y)

def do_this(x, y):
    ...

def do_that(x, y):
    ...
于 2012-06-22T10:44:34.890 に答える
2

いいえ、ありません。ネストされた関数内から外部スコープの変数にアクセスできるため、次のようになります。

def foo(x,y):
    def do_this(z):
        print(x,y,z)
    # ...

およびdo_thisのバインディングを提供しているときに呼び出す方法はありません。xy

他の場所から呼び出す必要がある場合はdo_this、それをと同じレベルのトップレベル関数にするだけfooです。

于 2012-06-22T10:44:01.593 に答える