[Python] 從 C# 的 Reflection 到 Python 的 Inspect

C# 寫久了,一定都會接觸到 reflection,它的使用上其實有一定的門檻。但寫習慣後,再去接觸 Python 的 inspect module,就會覺得簡單許多。

在介紹 inspect 之前,先看看以下定義的類別:

import inspect
import example_module

class BaseClass(object):

def __init__(self):
pass

class TestClass(BaseClass):

def __init__(self):
self.test_property = 0
self.test_property2 = 3065
print('TestClass init')

def foo(self):
return 0

def foo2(self, a, b, c):
return a + b + c

上面的程式碼,定義了一個 base class,以及繼承它的 class。接下來試著列出物件的資訊:

t = TestClass()
print('type of TestClass')
print(type(t))
print('base class')
print(type(t).__bases__)

執行結果如下:

TestClass init
type of TestClass
<class '__main__.TestClass'>
base class
(<class '__main__.BaseClass'>,)

如用 C# 來寫,大概會是這樣:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ReflectionConsoleApplication
{
class BaseClass
{
}

class TestClass : BaseClass
{
public int test_property { get; set; }
public int test_property2 { get; set; }
public TestClass()
{
this.test_property = 0;
this.test_property2 = 3065;
Console.WriteLine("TestClass init");
}

public int foo()
{
return 0;
}

public int foo2(int a, int b, int c)
{
return a + b + c;
}
}

class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass();
Console.WriteLine("type of TestClass:");
Console.WriteLine(t.GetType().Name);
Console.WriteLine("base class:");
Console.WriteLine(t.GetType().BaseType.Name);
}
}
}

如果只是單純印出型別名稱,C# 跟 Python 的差別可能不大。
接下來列出該物件裡的所有 method:

print('list members of object')
members_of_object = inspect.getmembers(t, predicate=inspect.ismethod)
for name, obj in members_of_object:
print(name)
print(obj)
print('')

使用方式非常直覺,在 getmembers 的 predicate 參數,是用來過濾資訊的,後面會提到其它的用法。

而它的執行結果如下:

TestClass init
list members of object
__init__
>

foo
>

foo2
>

而 C# 的寫法如下:

Console.WriteLine("list members of object");
MethodInfo[] members_of_object = t.GetType().GetMethods();
foreach (var method in members_of_object)
{
Console.WriteLine("name:");
Console.WriteLine(method.Name);
Console.WriteLine();
}

假如要動態的執行物件的 method,比 C# 簡單更多:

fun = getattr(t, 'foo')
print(fun())

只有短短兩行,對比 C# 的行數簡直天壤之別。如果 method 中有參數,有以下兩種執行方式:

fun = getattr(t, 'foo2')
kwargs = {'a': 1, 'b': 2, 'c': 3}
args = [1, 2, 3]
print('')
print(fun(**kwargs))
print(fun(*args))

我個人覺得將參數包成 dictionary 物件,對於程式的可讀性會比較好。
而在 C#,執行方法就會比較複雜些,雖然同樣也是兩行:

MethodInfo method = t.GetType().GetMethod("foo");
Console.WriteLine(method.Invoke(t, null));

同樣是兩行程式碼,在 C# 的方式就沒那麼的直覺。

最後介紹列出 module 資訊的方法,其實跟前面介紹的方法一樣,只是參數略為不同:

import example_module
print(inspect.getmembers(example_module, predicate=inspect.isfunction))

執行後,就會將 module 內所定義的 function 全部列出來。

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s