3

Python で流暢なインターフェイスを試しています。

流暢な sql クエリ ジェネレーターの使用例は、次のようになります。

sql.select('foo').select('bar').from('sometable').tostring() 

ネストされたクラスを再帰的に定義する機能がおそらく役立つことにすぐに気付きました。

class sql:
    class select:        
        class select   # <--  HERE
        def __init__(self, dbcolumn, astype=None, asname=None):
            self.dbcolumn = dbcolumn
            self.astype = astype
            self.asname = asname

コメント '# <-- HERE' でマークされた行:
このネストされたクラス参照が、含まれているクラスの同じ 'select' クラス定義を参照するようにします。

これはどういうわけか可能ですか?たぶん、私が気付いていないキーワードを使用していますか?

4

3 に答える 3

7

「再帰的なクラス定義」は必要ありません。チェーンを許可するために必要なselfのは、メソッド (または、オブジェクトが可変でない場合、または一部のメソッドが入力オブジェクトを変更してはならない場合は、同じクラスのインスタンス) を返すことだけです。

例:

>>> class SQL(object):
...     def __init__(self):
...         self.columns = []
...     def select(self, col):
...         self.columns.append(col)
...         return self
...
>>> s = SQL()
>>> s.select('foo').select('bar').columns
['foo', 'bar']
于 2012-07-25T08:36:22.763 に答える
0

質問のタイトルが示すように、クラス定義を再帰的にネストする方法を本当に知りたかったのです。'fluent-interface-in-pythoncat'のスキンを作成する方法はたくさんあると思います。

デコレータを使用してクラス定義を再帰的にネストする方法を見つけました。

# class decorator
def recursiveclass(decorated_class):
    decorated_class.__dict__[decorated_class.__name__] = decorated_class
    return decorated_class     

#fluent interface
class sql:
    @recursiveclass
    class select:        
        def __init__(self, dbcolumn, astype=None, asname=None):
            self.dbcolumn = dbcolumn
            self.astype = astype
            self.asname = asname

これがPythonで流暢なインターフェースを実装するための最良の方法であると言っているわけではないことに注意してください。私はただ実験しているだけです。

検証します:

dir(sql.select.select.select.select)
['__doc__', '__init__', '__module__', 'select']
于 2012-07-25T09:07:36.570 に答える
0

クラスメソッドを混同しています。

selectclass sqlネストされたクラスではなく、のインスタンスのメソッドです。別のインスタンスを返す可能性があります。

class SelectStatement(object):
    def select(self, tablename):
        return SelectStatement()

class SQL(object):
    def select(self, tablename):
        return SelectStatement()

SQLAlchemyのソース コードを見てください。まさにそれを行います。構造の Python クラスから SQL を生成します。この方法でインスタンスのメソッドを呼び出してクエリを絞り込むことができます。たとえば、一連の結合を連鎖させることができます。

q = session.query(User).join(User.orders).join(Order.items).join(Item.keywords)
于 2012-07-25T08:36:24.010 に答える