2011/09/28

SoftimageのオブジェクトをPythonクラスで拡張する

タイトルどおりSoftimageのオブジェクトをPythonクラスで拡張する方法。
これのミソは元々のSoftimageのオブジェクトの機能はちゃんと受け継いでるところです。
たとえばこんな感じ。
from win32com.client import *
si = Application

class MyObject(object):
    '''Softimageオブジェクトを拡張するクラス'''
    def __init__(self, input):
        '''初期化処理'''
        self.input = input  #元オブジェクトを格納


    def __getattr__(self, attr):
        '''このクラスにないアトリビュートが呼び出されたときに通る処理'''
        return getattr(self.input, attr)  #元オブジェクトのアトリビュートを取得して戻す


oNull = si.ActiveSceneRoot.AddNull() #ヌルを作成
MyNull= MyObject(oNull)                 #ヌルを引数に自前クラスのインスタンスを作成
LogMessage(MyNull.Name)
LogMessage(MyNull.posx.Value)
MyNull.AddNull('child')

これをSoftimageのスクリプトエディタに貼って実行するとどこにも定義してないけど.Nameも.posx.ValueもメソッドのAddNull()も使えます。

種は__getattr__とgetattrで、
__getattr__はクラスにないアトリビュートが呼ばれた時に実行されるメソッドで、呼び出そうとしたアトリビュートの代わりに戻り値を実行してくれるようです。
getattrは
getattr(オブジェクト, アトリビュート名)
でオブジェクトが持ってるアトリビュートを返してくれます。
なので
    def __getattr__(self, attr):
        return getattr(self.input, attr)
とすることで__getattr__を通る(存在しないアトリビュートが呼ばれた)時にインスタンスを作った時self.inputに格納しておいた元オブジェクトを使ってgetattr(self.input, attr)で元オブジェクトのアトリビュートを取得して実行するようになります。

これで好きな機能をバリバリ追加したカスタムオブジェクトが作れます。
たとえばこんな感じ。
アイコンを簡単に変更する機能をつけたヌルクラス

from win32com.client import *
si = Application

#ヌルアイコンの定数
NullIcon = {
   'None'       : 0,
   'Null'       : 1,
   'Rings'      : 2,
   'Arrow Rings': 4,
   'Box'        : 5,
   'Circle'     : 6,
   'Square'     : 7,
   'Diamond'    : 8,
   'Pyramid'    : 9,
   'Arrow'      : 10
   }


class MyNull(object):
 '''Nullを拡張するクラス'''
 def __init__(self, input):
  '''初期化処理'''
  self.input = input  #元オブジェクトを格納


 def __getattr__(self, attr):
  '''このクラスにないアトリビュートが呼び出されたときに通る処理'''
  return getattr(self.input, attr)  #元オブジェクトのアトリビュートを取得して戻す
  
  
 def SetIcon(self, sIconType='Null', nSize=1):
  '''アイコンを変更'''
  self.Parameters('primary_icon').Value = NullIcon[sIconType]
  self.Parameters('size').Value         = nSize
  
  
 def SetShadowIcon(self, sIconType='Null', nSize=1, lColor=[0,0,0]):
  '''
  シャドウアイコンを変更
  シャドウアイコンを変更するときはきっと通常のアイコンを使わないことが多いので非表示にする
  '''
  self.SetIcon('None', nSize) #通常のアイコンを非表示に
  self.Parameters('shadow_colour_custom').Value = True
  self.Parameters('shadow_icon').Value = NullIcon[sIconType]
  self.Parameters('R').Value = lColor[0]
  self.Parameters('G').Value = lColor[1]
  self.Parameters('B').Value = lColor[2]
  
  
oNull = si.ActiveSceneRoot.AddNull()     #ヌルを作成
Null = MyNull(oNull)                     #ヌルを引数に自前クラスのインスタンスを作成
Null.SetShadowIcon('Rings', 1, [1,1,0])  #シャドウアイコンを変更

2011/09/16

メソッドからクラス名を取得2

またまた自分用メモ。
こういうやり方もあるらしい。
これだとsys._getframe()の引数を変えることでクラスに限らずどんどんframeオブジェクトとやらを上がっていけるみたい。
import sys

def test():
	print sys._getframe(1).f_code.co_name

class TestClass:
    test()
 
T = TestClass()

2011/09/14

メソッドからクラス名を取得

自分メモ。
自分を呼び出したインスタンスのクラス名を表示。
class TestClass:
	def test(self):
		print locals()['self'].__class__.__name__

class TestClass2(TestClass):
	pass
		
T = TestClass()
T.test()

T = TestClass2()
T.test()

9/25 追記:
べつにこれでいいじゃん。。。
class TestClass:
	def test(self):
		print self.__class__.__name__

class TestClass2(TestClass):
	pass
		
T = TestClass()
T.test()

T = TestClass2()
T.test()
ま、なんかに使えるかな。きっと。