前の関連記事:LibreOffice5(48)Javaの例:ConfigExamplesをPythonにする その1
ConfigurationAccessサービスのインスタンスにProxyでメソッドを追加する
1 2 3 |
visible = root.getNode( "Option/VisibleGrid" ) resolution_x, resolution_y = root.getNode( "Resolution" ).getNode( "XAxis/Metric" , "YAxis/Metric" ) subdivision_x, subdivision_y = root.getNode( "Subdivision" ).getNode( "XAxis" , "YAxis" ) |
ConfigurationAccessサービスのgetHierarchicalPropertyValue()、getHierarchicalPropertyValues()、getPropertyValue()、getPropertyValues()の4つのメソッドをgetNode()という一つのメソッドで処理することになります。
サービスがクラスとして扱えて継承できれば、getNode()をメソッドの一つに加えて、インスタンスを返すようにすればよいかな、と考えましたが、サービスをクラスとして扱う方法がそもそもわからないので、サブクラスを作る方法については追及しませんでした。
で、Python Cookbook
example2.pyのクラスProxyを使うとメソッドを追加したインスタンスを引数にしてProxyクラスをインスタンス化するだけで、Proxyクラスに追加したメソッドが引数のインスタンスに追加できます。
linuxBean14.04(170)Pythonのデスクリプタの学習を少しで使ったtypes.MethodType()でもインスタンスにメソッドを追加できますが、メソッドチェーンにするためにはオブジェクトを返す方法を別に考えないといけないので面倒です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Proxy: def __init__( self , obj): self ._obj = obj def getNode( self , * args): delimset = { "/" , "." , ":" } if len (args) = = 1 : node = self ._obj.getHierarchicalPropertyValue( * args) if delimset & set ( * args) else self ._obj.getPropertyValue( * args) return Proxy(node) if hasattr (node, "getTypes" ) else node elif len (args)> 1 : nodes = self ._obj.getHierarchicalPropertyValues(args) if delimset & set ("".join(args)) else self ._obj.getPropertyValues(args) return [Proxy(node) if hasattr (node, "getTypes" ) else node for node in nodes] def __getattr__( self , name): return getattr ( self ._obj, name) def __setattr__( self , name, value): super ().__setattr__(name, value) if name.startswith( '_' ) else setattr ( self ._obj, name, value) def __delattr__( self , name): super ().__delattr__(name) if name.startswith( '_' ) else delattr ( self ._obj, name) |
getNode()では引数の数が一つか複数かで場合分けしたあとさらに引数の文字列の中にスラッシュかドット、コロンのいずれかの文字があるかで場合分けして4つのメソッドに振り分けています。
戻り値の属性にgetTypesがあればPyUNOオブジェクトとしてまたProxyの引数にしてProxyオブジェクトを返し、そうでなければ値としてそのまま返しています。
Javaの例ではcom.sun.star.uno.AnyConverterのisObjectメソッドを使ってPyUNOオブジェクトかどうか調べています。
このisObjectメソッドではinterface, struct, exception, sequence, enumであるか調べてTrueを返しています。
Pythonで利用できる同じ働きをする関数を探してみましたが見つけられませんでした。
なので、getTypesがあるかどうかでPyUNOオブジェクトかどうかを判断しています。
(2017.6.18追記。PyUNOオブジェクトをtype()にかけると<class 'pyuno'>が返ってくるのでtype(object).__name__=="pyuno"で判定することにしました。)
あとはConfigurationAccessサービスのインスタンスをこのProxyクラスの引数にしてインスタンス化すればgetNode()メソッドが使えるようになります。
1 2 3 4 5 6 7 8 |
def readGridConfiguration(cp): ca = createConfigurationView( "/org.openoffice.Office.Calc/Grid" , cp) root = Proxy(ca) visible = root.getNode( "Option/VisibleGrid" ) resolution_x, resolution_y = root.getNode( "Resolution" ).getNode( "XAxis/Metric" , "YAxis/Metric" ) subdivision_x, subdivision_y = root.getNode( "Subdivision" ).getNode( "XAxis" , "YAxis" ) ca.dispose() return GridOptions(visible, resolution_x, resolution_y, subdivision_x, subdivision_y) |
プロパティに代わってcollections.namedtuple()を使う
readGridConfiguration()はGridOptionのインスタンスを返しています。
1 2 3 4 5 |
class GridOptions(namedtuple( "GridOptions" , "visible resolution_x resolution_y subdivision_x subdivision_y" )): __slots__ = () def __str__( self ): return "[ Grid is {0}; resolution = ({1},{2}); subdivision = ({3},{4}) ]" \ . format ( "VISIBLE" if self .visible else "HIDDEN" , self .resolution_x, self .resolution_y, self .subdivision_x, self .subdivision_y) |
namedtuple自体はPython Cookbook
linuxBean14.04(170)Pythonのデスクリプタの学習を少しで学習したプロパティを使うとオーバーヘッドが大きくなるのですが、namedtupleを使うとタプルより少しオーバーヘッドが増えるだけだそうです。
__slots__はPythonの標準ライブラリのドキュメントの例にあるままに使っています。
Python Cookbook
ConfigExamples/configexamples.py at 0c8e666083c27de6b988eb1d627a64273049f919 · p--q/ConfigExamples
readDataExample()はこれで翻訳完了です。
参考にしたサイト
AnyConverter (Java UNO Runtime Reference)
JavaでUNOタイプの判定や変換をするクラス。
8.3. collections — コンテナデータ型 — Python 3.6.1 ドキュメント
namedtupleの解説。
3. データモデル — Python 3.6.1 ドキュメント
__slots__の解説。
0 件のコメント:
コメントを投稿