IronPython .NET Integration官方文檔翻譯筆記(待整理,持續更新中...)

来源:http://www.cnblogs.com/kurozaki/archive/2017/01/10/6270198.html
-Advertisement-
Play Games

恢復內容開始 http://ironpython.net/documentation/dotnet/這是原文地址 以下筆記僅記錄閱讀過程中我認為有必要記錄的內容,大多數都是依賴翻譯軟體的機翻,配合個人對代碼的理解寫出的筆記,個別不是很確定的,會在句首標註 猜測: 在ironPython 中想使用.N ...


---恢復內容開始---

http://ironpython.net/documentation/dotnet/這是原文地址

以下筆記僅記錄閱讀過程中我認為有必要記錄的內容,大多數都是依賴翻譯軟體的機翻,配合個人對代碼的理解寫出的筆記,個別不是很確定的,會在句首標註   猜測:

在ironPython 中想使用.Net的API必須先導入 CLR,借用CLR導入.Net的類,最常用的是下麵這種導法

>>> import clr
>>> clr.AddReference("System.Xml")

All .NET assemblies have a unique version number which allows using a specific version of a given assembly. The following code will load the version of System.Xml.dll that ships with .NET 2.0 and .NET 3.5:

同樣支持輸入更詳細的程式集信息來導入指定版本的.Net類

>>> import clr
>>> clr.AddReference("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

在CLR引入.Net大類之後,就可以使用Python代碼正式導入這些類,在IronPython中,會將這些.Net 轉化為Python類來對待,但如果使用類示例對比,會發現無論你對比的是.Net類還是Python類,都成立。
可以使用import 直接導入命名空間下所有東西,也可以用from x import x【,x...】的語法選擇性的導入個別需要被用到的類
>>> import System
>>> System #doctest: +ELLIPSIS
<module 'System' (CLS module, ... assemblies loaded)>
>>> System.Collections #doctest: +ELLIPSIS
<module 'Collections' (CLS module, ... assemblies loaded)>

The types in the namespaces are exposed as Python types, and are accessed as attributes of the namespace. The following code accesses the System.Environment class from mscorlib.dll:

>>> import System
>>> System.Environment
<type 'Environment'>

Just like with normal Python modules, you can also use all the other forms of import as well:

>>> from System import Environment
>>> Environment
<type 'Environment'>
>>> from System import *
>>> Environment
<type 'Environment'>

在ironPython里你可以用這樣的語法來表示.net中的泛型
>>> from System.Collections.Generic import List, Dictionary
>>> int_list = List[int]()
>>> str_float_dict = Dictionary[str, float]()

Note that there might exist a non-generic type as well as one or more generic types with the same name [1]. In this case, the name can be used without any indexing to access the non-generic type, and it can be indexed with different number of types to access the generic type with the corresponding number of type parameters. The code below accesses System.EventHandler and also System.EventHandler<TEventArgs>

在.Net中很多類型都有泛型和非泛型版本,比如下麵這個例子,用泛型和非泛型版本你將訪問不同類型的對象,使用python的dir方法可以明顯看出檢索出來的方法屬性列表是不同的

>>> from System import EventHandler, EventArgs
>>> EventHandler # this is the combo type object
<types 'EventHandler', 'EventHandler[TEventArgs]'>
>>> # Access the non-generic type
>>> dir(EventHandler) #doctest: +ELLIPSIS
['BeginInvoke', 'Clone', 'DynamicInvoke', 'EndInvoke', ...
>>> # Access the generic type with 1 type paramter
>>> dir(EventHandler[EventArgs]) #doctest: +ELLIPSIS
['BeginInvoke', 'Call', 'Clone', 'Combine', ...


很多時候在IronPython 中並不支持一口氣導入整個命名空間里所有東西

.NET types are exposed as Python classes. Like Python classes, you usually cannot import all the attributes of .NET types using from <name> import *:

>>> from System.Guid import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: no module named Guid

You can import specific members, both static and instance:

你通常只能這樣玩,需要什麼,導入什麼

>>> from System.Guid import NewGuid, ToByteArray
>>> g = NewGuid()
>>> ToByteArray(g) #doctest: +ELLIPSIS
Array[Byte](...

Note that if you import a static property, you will import the value when the import executes, not a named object to be evaluated on every use as you might mistakenly expect:

當你導入個別靜態屬性時,其實你只是導入了一個值類型,如果你用全名稱來對比,你會發現無法對等(這句話意思其實有點難理解,反正看代碼就知道大概意思)

>>> from System.DateTime import Now
>>> Now #doctest: +ELLIPSIS
<System.DateTime object at ...>
>>> # Let's make it even more obvious that "Now" is evaluated only once
>>> a_second_ago = Now
>>> import time
>>> time.sleep(1)
>>> a_second_ago is Now
True
>>> a_second_ago is System.DateTime.Now
False


Some .NET types only have static methods, and are comparable to namespaces. C# refers to them as static classes , and requires such classes to have only static methods. IronPython allows you to import all the static methods of such static classesSystem.Environment is an example of a static class:

有些.net類只包含靜態方法,你可以像這樣導入

>>> from System.Environment import *
>>> Exit is System.Environment.Exit
True

Nested types are also imported:

>>> SpecialFolder is System.Environment.SpecialFolder
True

However, properties are not imported:

然而你會發現只有靜態方法被導進來了,靜態屬性並沒有被導進來(這和上一段看起來有點矛盾,難理解。不過寫代碼的時候自己試一試就知道能不能行得通了)

>>> OSVersion
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'OSVersion' is not defined
>>> System.Environment.OSVersion #doctest: +ELLIPSIS
<System.OperatingSystem object at ...>


下麵這段大概是說在IronPython里導入.Net類型,如果用類型對比你會發現,他即可當做.Net類也可以當做Python類

.NET represents types using System.Type. However, when you access a .NET type in Python code, you get a Python type object [2]:

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> isinstance(type(ba), type)
True

This allows a unified (Pythonic) view of both Python and .NET types. For example, isinstance works with .NET types as well:

>>> from System.Collections import BitArray
>>> isinstance(ba, BitArray)
True

If need to get the System.Type instance for the .NET type, you need to use clr.GetClrType. Conversely, you can use clr.GetPythonType to get a type object corresponding to a System.Type object.

The unification also extends to other type system entities like methods. .NET methods are exposed as instances of method:

這段很難理解,看不懂

>>> type(BitArray.Xor)
<type 'method_descriptor'>
>>> type(ba.Xor)
<type 'builtin_function_or_method'>
下麵這條我猜他是想說如果按照實例來對比.Net類可以等於Python類,但按照類型來對比,兩者並不對等

Note that the Python type corresponding to a .NET type is a sub-type of type:

>>> isinstance(type(ba), type)
True
>>> type(ba) is type
False

This is an implementation detail.

這段說的是從.Net那邊導進來的類,你不能隨意刪除裡面的方法和屬性

.NET types behave like builtin types (like list), and are immutable. i.e. you cannot add or delete descriptors from .NET types:

>>> del list.append
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: cannot delete attribute 'append' of builtin type 'list'
>>>
>>> import System
>>> del System.DateTime.ToByteArray
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'DateTime'


下麵這段是說你可以把.Net類用Python的語法來實例化,也可以調用new方法來實例化,我覺得在python里new看著特彆扭,還是入鄉隨俗吧。

.NET types are exposed as Python classes, and you can do many of the same operations on .NET types as with Python classes. In either cases, you create an instance by calling the type:

>>> from System.Collections import BitArray
>>> ba = BitArray(5) # Creates a bit array of size 5

IronPython also supports inline initializing of the attributes of the instance. Consider the following two lines:

>>> ba = BitArray(5)
>>> ba.Length = 10

The above two lines are equivalent to this single line:

>>> ba = BitArray(5, Length = 10)

You can also call the __new__ method to create an instance:

>> ba = BitArray.__new__(BitArray, 5)


在python里使用.Net類型其實和在.Net中使用方式相似(可以說一模一樣)

Invoking .NET instance methods works just like invoking methods on a Python object using the attribute notation:

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> ba.Set(0, True) # call the Set method
>>> ba[0]
True

IronPython also supports named arguments:

也支持命名參數

>>> ba.Set(index = 1, value = True)
>>> ba[1]
True

IronPython also supports dict arguments:

他還支持字典式傳參,這招在.Net里是沒有的,通過下麵這個例子你會發現,你可以在使用過程中逐步收集參數,按照順序放入集合里,最後再丟進一個方法。

>>> args = [2, True] # list of arguments
>>> ba.Set(*args)
>>> ba[2]
True

IronPython also supports keyword arguments:

也支持使用鍵值對字典給方法傳參(爽)

>>> args = { "index" : 3, "value" : True }
>>> ba.Set(**args)
>>> ba[3]
True


在IronPython里如果傳入的參數不符合方法需要的參數類型,那麼它會結合.Net和Python的綜合規則來進行強制轉化,比如下麵這個例子,他會把string轉成數字,數字大於1就等於bool的true,然後None是Python里的null等同於false

When the argument type does not exactly match the parameter type expected by the .NET method, IronPython tries to convert the argument. IronPython uses conventional .NET conversion rules like conversion operators , as well as IronPython-specific rules. This snippet shows how arguments are converted when calling theSet(System.Int32, System.Boolean) method:

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> ba.Set(0, "hello") # converts the second argument to True.
>>> ba[0]
True
>>> ba.Set(1, None) # converts the second argument to False.
>>> ba[1]
False

See appendix-type-conversion-rules for the detailed conversion rules. Note that some Python types are implemented as .NET types and no conversion is required in such cases. See builtin-type-mapping for the mapping.

Some of the conversions supported are:

Python argument type.NET method parameter type
int System.Int8, System.Int16
float System.Float
tuple with only elements of type T System.Collections.Generic.IEnumerable<T>
function, method System.Delegate and any of its sub-classes


在IronPython中同樣支持.net中的函數重載,解釋器會自動匹配最適合的那個重載

.NET supports overloading methods by both number of arguments and type of arguments. When IronPython code calls an overloaded method, IronPython tries to select one of the overloads at runtime based on the number and type of arguments passed to the method, and also names of any keyword arguments. In most cases, the expected overload gets selected. Selecting an overload is easy when the argument types are an exact match with one of the overload signatures:

>>> from System.Collections import BitArray
>>> ba = BitArray(5) # calls __new__(System.Int32)
>>> ba = BitArray(5, True) # calls __new__(System.Int32, System.Boolean)
>>> ba = BitArray(ba) # calls __new__(System.Collections.BitArray)

The argument types do not have be an exact match with the method signature. IronPython will try to convert the arguments if an unamibguous conversion exists to one of the overload signatures. The following code calls __new__(System.Int32) even though there are two constructors which take one argument, and neither of them accept a float as an argument:

猜測:即使調用一個不存在的重載,IronPython也允許將參數強轉後找到最適合匹配的那個重載

>>> ba = BitArray(5.0)

However, note that IronPython will raise a TypeError if there are conversions to more than one of the overloads:

猜測:註意,如果傳入的參數需要被進行1次以上的強轉才能找到匹配的話,那麼將報錯

>>> BitArray((1, 2, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Multiple targets could match: BitArray(Array[Byte]), BitArray(Array[bool]), BitArray(Array[int])

If you want to control the exact overload that gets called, you can use the Overloads method on method objects:

你也可以強制指定接下來的代碼必須匹配函數的哪種重載,例如下麵代碼,最後一次試圖只傳入1個參數,那麼將會報錯

>>> int_bool_new = BitArray.__new__.Overloads[int, type(True)]
>>> ba = int_bool_new(BitArray, 5, True) # calls __new__(System.Int32, System.Boolean)
>>> ba = int_bool_new(BitArray, 5, "hello") # converts "hello" to a System.Boolan
>>> ba = int_bool_new(BitArray, 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __new__() takes exactly 2 arguments (1 given)

TODO - Example of indexing Overloads with an Array, byref, etc using Type.MakeByrefType

 

猜測:在IronPython中允許一種特殊的調用方式,不同.Net,在.net中我們只能調用子類中實現了介面或者虛方法的方法,但在IronPython中允許直接調用介面中的方法或者虛類中的虛方法,解釋器能自動找到匹配的那個實現,例如下麵的代碼,因為string繼承

object所以也有Clone方法,調用ICloneable的虛方法Clone,傳入參數string,那麼解釋器會去string類型里尋找Clone方法

It is sometimes desirable to invoke an instance method using the unbound class instance method and passing an explicit self object as the first argument. For example, .NET allows a class to declare an instance method with the same name as a method in a base type, but without overriding the base method. SeeSystem.Reflection.MethodAttributes.NewSlot for more information. In such cases, using the unbound class instance method syntax allows you chose precisely which slot you wish to call:

>>> import System
>>> System.ICloneable.Clone("hello") # same as : "hello".Clone()
'hello'

The unbound class instance method syntax results in a virtual call, and calls the most derived implementation of the virtual method slot:

猜測:所以object的GetHashCode和String的GetHashCode是一樣的,因為string 繼承於object,但是string的GetHashCode方法和RunTimeHelpers類中的GetHashCode不同,猜測,可能是因為具體實現不同,解釋器能夠通過IL代碼分辨出實現是否一致?

>>> s = "hello"
>>> System.Object.GetHashCode(s) == System.String.GetHashCode(s)
True
>>> from System.Runtime.CompilerServices import RuntimeHelpers
>>> RuntimeHelpers.GetHashCode(s) == System.String.GetHashCode(s)
False

猜測:下麵這段大概是講.Net里方法的實現分為顯式和隱式兩種,比如說在.Net里如果顯式實現方法,那麼我們只能用介面才能調用,如果隱式實現,那麼直接在實現類或者介面中都可以調用。

但是IronPython中似乎沒有這種限制,只要實現了,就都可以調用。最後一節推測大概是說,如果實現類中存在同名的方法(顯式實現),那麼最好還是用介面來調用,才準確無誤。

.NET allows a method with a different name to override a base method implementation or interface method slot. This is useful if a type implements two interfaces with methods with the same name. This is known as explicity implemented interface methods. For example, Microsoft.Win32.RegistryKey implementsSystem.IDisposable.Dispose explicitly:

>>> from Microsoft.Win32 import RegistryKey
>>> clr.GetClrType(RegistryKey).GetMethod("Flush") #doctest: +ELLIPSIS
<System.Reflection.RuntimeMethodInfo object at ... [Void Flush()]>
>>> clr.GetClrType(RegistryKey).GetMethod("Dispose")
>>>

In such cases, IronPython tries to expose the method using its simple name - if there is no ambiguity:

>>> from Microsoft.Win32 import Registry
>>> rkey = Registry.CurrentUser.OpenSubKey("Software")
>>> rkey.Dispose()

However, it is possible that the type has another method with the same name. In that case, the explicitly implemented method is not accessible as an attribute. However, it can still be called by using the unbound class instance method syntax:

>>> rkey = Registry.CurrentUser.OpenSubKey("Software")
>>> System.IDisposable.Dispose(rkey)


在這裡Python和.Net調用靜態方法的方式是一樣的

Invoking static .NET methods is similar to invoking Python static methods:

>>> System.GC.Collect()

Like Python static methods, the .NET static method can be accessed as an attribute of sub-types as well:

.Net的靜態方法會以Python的規則,方法會被認為是一個類的一個屬性,推測:下麵這2個類的同名方法如果實現是一樣的,那麼對比起來結果就是一樣的

>>> System.Object.ReferenceEquals is System.GC.ReferenceEquals
True

TODO What happens if the sub-type has a static method with the same name but a different signature? Are both overloads available or not?

 

展示如何調用泛型方法

Generic methods are exposed as attributes which can be indexed with type objects. The following code calls System.Activator.CreateInstance<T>

>>> from System import Activator, Guid
>>> guid = Activator.CreateInstance[Guid]()


下麵這段展示了在IronPython中也支持泛型的自動推斷功能,比如最後一段
Enumerable.Any[int](list, lambda x : x < 2)
Enumerable.Any(list, lambda x : x < 2)
解釋器會自動匹配適合的泛型,寫的時候就可以省略泛型,另外讓我驚奇的是這裡頭居然也支持lambda,真是屌爆了

In many cases, the type parameter can be inferred based on the arguments passed to the method call. Consider the following use of a generic method [3]:

>>> from System.Collections.Generic import IEnumerable, List
>>> list = List[int]([1, 2, 3])
>>> import clr
>>> clr.AddReference("System.Core")
>>> from System.Linq import Enumerable
>>> Enumerable.Any[int](list, lambda x : x < 2)
True

With generic type parameter inference, the last statement can also be written as:

>>> Enumerable.Any(list, lambda x : x < 2)
True

See appendix for the detailed rules.

 

下麵這段大概是說在IronPython里沒有像很多高級語言中有 ref和out的概念,在IronPython中對於這種輸出引用有兩種玩法,一種隱式的一種顯式的

The Python language passes all arguments by-value. There is no syntax to indicate that an argument should be passed by-reference like there is in .NET languages like C# and VB.NET via the ref and out keywords. IronPython supports two ways of passing ref or out arguments to a method, an implicit way and an explicit way.

下麵展示的第一種是隱式的,直接調用方法,比如說原來.Net字典里的TryGetValue方法,原本要傳入一個key和一個out引用參數,返回bool結果表示有沒找到,但是在IronPython中隱式實現只要直接調用方法,傳入key就行了,返回一個元組類型的返回值,裡面包含了方法返回值和引用輸出返回值。

In the implicit way, an argument is passed normally to the method call, and its (potentially) updated value is returned from the method call along with the normal return value (if any). This composes well with the Python feature of multiple return values. System.Collections.Generic.Dictionary has a method bool TryGetValue(K key, out value). It can be called from IronPython with just one argument, and the call returns a tuple where the first element is a boolean and the second element is the value (or the default value of 0.0 if the first element is False):

>>> d = { "a":100.1, "b":200.2, "c":300.3 }
>>> from System.Collections.Generic import Dictionary
>>> d = Dictionary[str, float](d)
>>> d.TryGetValue("b")
(True, 200.2)
>>> d.TryGetValue("z")
(False, 0.0)

下麵展示的是顯式實現,說明裡說假如方法存在多種重載的話,這種方式很好用,例如下麵的例子,使用CLR的方法生成一個float類型的引用對象,傳給方法,然後就和.Net玩法一模一樣了,方法還是只返回bool,輸出的值將通過引用對象的Value屬性來讀取,有點像.Net里的可空類型

In the explicit way, you can pass an instance of clr.Reference[T] for the ref or out argument, and its Value field will get set by the call. The explicit way is useful if there are multiple overloads with ref parameters:

>>> import clr
>>> r = clr.Reference[float]()
>>> d.TryGetValue("b", r)
True
>>> r.Value
200.2

Extension methods

目前IronPython對於擴展方法的支持還不好,不能像C#那樣直接調用,只能通過靜態方法來調用,例如,假設string有一個substring方法是後來擴展的,在c#你可以寫成"sadsad".substring(...),但是在IronPython你只能寫成System.String.SubString("sadsad")

Extension methods are currently not natively supported by IronPython. Hence, they cannot be invoked like instance methods. Instead, they have to be invoked like static methods.

 

下麵這段大概是說,在.Net里有索引器的概念,我們可以像下麵這樣去方便的訪問集合中的某個對象,

.NET indexers are exposed as __getitem__ and __setitem__. Thus, the Python indexing syntax can be used to index .NET collections (and any type with an indexer):

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> ba[0]
False
>>> ba[0] = True
>>> ba[0]
True

但是,也支持使用比較麻煩老土的get和set來訪問對象,就像下麵這樣

The indexer can be called using the unbound class instance method syntax using __getitem__ and __setitem__. This is useful if the indexer is virtual and is implemented as an explicitly-implemented interface method:

>>> BitArray.__getitem__(ba, 0)
True

Non-default .NET indexers

這段看不懂

Note that a default indexer is just a property (typically called Item) with one argument. It is considered as an indexer if the declaraing type uses DefaultMemberAttribute to declare the property as the default member.

See property-with-parameters for information on non-default indexers.

 

在.Net中一個屬性都有一對Get和Set方法,所以在Python中調用.Net屬性進行讀寫,實際上後臺操作也是調用屬性的get和set方法來進行

.NET properties are exposed similar to Python attributes. Under the hood, .NET properties are implemented as a pair of methods to get and set the property, and IronPython calls the appropriate method depending on whether you are reading or writing to the properity:

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> ba.Length # calls "BitArray.get_Length()"
5
>>> ba.Length = 10 # calls "BitArray.set_Length()"

上面的代碼相當於下麵的代碼,效果一樣

To call the get or set method using the unbound class instance method syntax, IronPython exposes methods called GetValue and SetValue on the property descriptor. The code above is equivalent to the following:

>>> ba = BitArray(5)
>>> BitArray.Length.GetValue(ba)
5
>>> BitArray.Length.SetValue(ba, 10)


下麵這段大概是說在IronPython里索引.Net類型中的集合數組的方式以及訪問屬性的方式,直接訪問屬性,調用get/set, 調用 對象.Item[?]的方式訪問對象

.NET properties are exposed similar to Python attributes. Under the hood, .NET properties are implemented as a pair of methods to get and set the property, and IronPython calls the appropriate method depending on whether you are reading or writing to the properity:

>>> from System.Collections import BitArray
>>> ba = BitArray(5)
>>> ba.Length # calls "BitArray.get_Length()"
5
>>> ba.Length = 10 # calls "BitArray.set_Length()"

To call the get or set method using the unbound class instance method syntax, IronPython exposes methods called GetValue and SetValue on the property descriptor. The code above is equivalent to the following:

>>> ba = BitArray(5)
>>> BitArray.Length.GetValue(ba)
5
>>> BitArray.Length.SetValue(ba, 10)

Properties with parameters

COM and VB.NET support properties with paramters. They are also known as non-default indexers. C# does not support declaring or using properties with parameters.

IronPython does support properties with parameters. For example, the default indexer above can also be accessed using the non-default format as such:

>>> ba.Item[0]
False

.net的事件可以使用+= 和-=的形式進行註冊和卸載,在IronPython中同樣支持這種玩法,下麵的代碼里用python 代碼按照.Net的格式定義了一個回調函數,居然也能註冊到.Net事件里去,真爽

.NET events are exposed as objects with __iadd__ and __isub__ methods which allows using += and -= to subscribe and unsubscribe from the event. The following code shows how to subscribe a Python function to an event using +=, and unsubscribe using -=

>>> from System.IO import FileSystemWatcher
>>> watcher = FileSystemWatcher(".")
>>> def callback(sender, event_args):
...     print event_args.ChangeType, event_args.Name
>>> watcher.Created += callback
>>> watcher.EnableRaisingEvents = True
>>> import time
>>> f = open("test.txt", "w+"); time.sleep(1)
Created test.txt
>>> watcher.Created -= callback
>>>
>>> # cleanup
>>> import os
>>> f.close(); os.remove("test.txt")

You can also subscribe using a bound method:

你也可以這樣寫,下麵代碼把回調寫在一個類裡頭而已,感覺並沒有什麼卵用,看起來更麻煩了

>>> watcher = FileSystemWatcher(".")
>>> class MyClass(object):
...     def callback(self, sender, event_args):
...         print event_args.ChangeType, event_args.Name
>>> o = MyClass()
>>> watcher.Created += o.callback
>>> watcher.EnableRaisingEvents = True
>>> f = open("test.txt", "w+"); time.sleep(1)
Created test.txt
>>> watcher.Created -= o.callback
>>>
>>> # cleanup
>>> f.close(); os.remove("test.txt")

You can also explicitly create a delegate instance to subscribe to the event. Otherwise, IronPython automatically does it for you. [4]:

也可以顯示定義一個委托

>>> watcher = FileSystemWatcher(".")
>>> def callback(sender, event_args):
...     print event_args.ChangeType, event_args.Name
>>> from System.IO import FileSystemEventHandler
>>> delegate = FileSystemEventHandler(callback)
>>> watcher.Created += delegate
>>> watcher.EnableRaisingEvents = True
>>> import time
>>> f = open("test.txt", "w+"); time.sleep(1)
Created test.txt
>>> watcher.Created -= delegate
>>>
>>> # cleanup
>>> f.close(); os.remove("test.txt")
他說顯示定義委托可以使程式記憶體占用更少,不知為何。。。難道他指的是裝箱和拆箱過程的性能損耗? The only advantage to creating an explicit delegate is that it is uses less memory. You should consider it if you subscribe to lots of events, and notice excessive System.WeakReference objects.  

下麵這段主要展示了怎麼使用python語法實例化.net數組和索引數組中的值

IronPython supports indexing of System.Array with a type object to access one-dimensional strongly-typed arrays:

>>> System.Array[int]
<type 'Array[int]'>

IronPython also adds a __new__ method that accepts a IList<T> to initialize the array. This allows using a Python list literal to initialize a .NET array:

>>> a = System.Array[int]([1, 2, 3])

Further, IronPython exposes __getitem__ and __setitem__ allowing the array objects to be indexed using the Python indexing syntax:

>>> a[2]
3

假如用GetValue索引一個負數,會報錯,你只能像a[-1]這種索引方式才不會報錯

Note that the indexing syntax yields Python semantics. If you index with a negative value, it results in indexing from the end of the array, whereas .NET indexing (demonstrated by calling GetValue below) raises a System.IndexOutOfRangeException exception:

>>> a.GetValue(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: Index was outside the bounds of the array.
>>> a[-1]
3

同樣也支持python 中的數組分割語法

Similarly, slicing is also supported:

>>> a[1:3]
Array[int]((2, 3))

.NET Exceptions

raise語句支持拋出.net和python中的異常

raise can raise both Python exceptions as well as .NET exceptions:

>>> raise ZeroDivisionError()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError
>>> import System
>>> raise System.DivideByZeroException()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: Attempted to divide by zero.

except關鍵字也可以catch兩種語言中的異常

The except keyword can catch both Python exceptions as well as .NET exceptions:

>>> try:
...    import System
...    raise System.DivideByZeroException()
... except System.DivideByZeroException:
...    print "This line will get printed..."
...
This line will get printed...
>>>


前面有一個例子講過,如果引用.Net對象,是不允許刪除和修改對象中的成員,在下麵例子中,也一樣,如果是python的異常ZeroDivisionError,那麼這是一個python類,允許隨意修改,比如在裡面加一個foo屬性,但是換成System.DivideByZeroException就

不行了,因為這是一個.Net對象,如果試圖修改,就會報錯

IronPython implements the Python exception mechanism on top of the .NET exception mechanism. This allows Python exception thrown from Python code to be caught by non-Python code, and vice versa. However, Python exception objects need to behave like Python user objects, not builtin types. For example, Python code can set arbitrary attributes on Python exception objects, but not on .NET exception objects:

>>> e = ZeroDivisionError()
>>> e.foo = 1 # this works
>>> e = System.DivideByZeroException()
>>> e.foo = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'DivideByZeroException' object has no attribute 'foo'

下麵這段寫了一大堆,大概意思就是說如果在IrinPython中,你寫的是python代碼,那隻會catch到python類型的異常,.Net則是catch到.Net類型的異常,但是,通過捕獲到的異常對象的clsException對象可以得到兩種語言公共的異常類,這是靠CLS(公共語言系統)來維護的。

To support these two different views, IronPython creates a pair of objects, a Python exception object and a .NET exception object, where the Python type and the .NET exception type have a unique one-to-one mapping as defined in the table below. Both objects know about each other. The .NET exception object is the one that actually gets thrown by the IronPython runtime when Python code executes a raise statement. When Python code uses the except keyword to catch the Python exception, the Python exception object is used. However, if the exception is caught by C# (for example) code that called the Python code, then the C# code naturally catches the .NET exception object.

The .NET exception object corresponding to a Python exception object can be accessed by using the clsException attribute (if the module has excecuted import clr):

>>> import clr
>>> try:
...     1/0
... except ZeroDivisionError as e:
...     pass
>>> type(e)
<type 'exceptions.ZeroDivisionError'>
>>> type(e.clsException)
<type 'DivideByZeroException'>

推測:下麵這段大概是說通過clsException對象中的Data可以索引到異常對應的Python版的異常

IronPython is also able to access the Python exception object corresponding to a .NET exception object [5], thought this is not exposed to the user [6].

[5]

The Python exception object corresponding to a .NET exception object is accessible (to the IronPython runtime) via the System.Exception.Data property. Note that this is an implementation detail and subject to change:

>>> e.clsException.Data["PythonExceptionInfo"] #doctest: +ELLIPSIS
<IronPython.Runtime.Exceptions.PythonExceptions+ExceptionDataWrapper object at ...>

下麵是2種語言的常見異常類型對照表

[6] ... except via the DLR Hosting API ScriptEngine.GetService<ExceptionOperations>().GetExceptionMessage
Python exception.NET exception
   
Exception System.Exception  
SystemExit   IP.O.SystemExit
StopIteration System.InvalidOperationException subtype  
StandardError System.SystemException  
KeyboardInterrupt   IP.O.KeyboardInterruptException
ImportError   IP.O.PythonImportError
EnvironmentError   IP.O.PythonEnvironmentError
IOError System.IO.IOException  
OSError S.R.InteropServices.ExternalException  
WindowsError System.ComponentModel.Win32Exception  
EOFError System.IO.EndOfStreamException  
RuntimeError IP.O.RuntimeException  
NotImplementedError System.NotImplementedException  
NameError   IP.O.NameException
UnboundLocalError   IP.O.UnboundLocalException
AttributeError System.MissingMemberException  
SyntaxError   IP.O.SyntaxErrorException (System.Data has something close)
IndentationError   IP.O.IndentationErrorException
TabError   IP.O.TabErrorException
TypeError   Microsoft.Scripting.ArgumentTypeException
AssertionError   IP.O.AssertionException
LookupError   IP.O.LookupException
IndexError System.IndexOutOfRangeException  
KeyError S.C.G.KeyNotFoundException  
ArithmeticError System.ArithmeticException  
OverflowError System.OverflowException  
ZeroDivisionError System.DivideByZeroException  
FloatingPointError   IP.O.PythonFloatingPointError
ValueError ArgumentException  
UnicodeError   IP.O.UnicodeException
UnicodeEncodeError System.Text.EncoderFallbackException  
UnicodeDecodeError System.Text.DecoderFallbackException  
UnicodeTranslateError   IP.O.UnicodeTranslateException
ReferenceError   IP.O.ReferenceException
SystemError   IP.O.PythonSystemError
MemoryError System.OutOfMemoryException  
Warning System.ComponentModel.WarningException  
UserWarning   IP.O.PythonUserWarning
DeprecationWarning   IP.O.PythonDeprecationWarning
PendingDeprecationWarning   IP.O.PythonPendingDeprecationWarning
SyntaxWarning   IP.O.PythonSyntaxWarning
OverflowWarning   IP.O.PythonOverflowWarning
RuntimeWarning   IP.O.PythonRuntimeWarning
FutureWarning   IP.O.PythonFutureWarning

 

下麵又講了一大堆,大概意思就是演示了一下如何在一段代碼中既捕獲.Net異常又捕獲Python異常,最後證實了兩種異常在CLS中,其實.net才是大哥,它才是參照標準。

Given that raise results in the creation of both a Python exception object and a .NET exception object, and given that rescue can catch both Python exceptions and .NET exceptions, a question arises of which of the exception objects will be used by the rescue keyword. The answer is that it is the type used in the rescue clause. i.e. if the rescue clause uses the Python exception, then the Python exception object will be used. If the rescue clause uses the .NET exception, then the .NET exception object will be used.

The following example shows how 1/0 results in the creation of two objects, and how they are linked to each other. The exception is first caught as a .NET exception. The .NET exception is raised again, but is then caught as a Python exception:

>>> import System
>>> try:
...     try:
...         1/0
...     except System.DivideByZeroException as e1:
...         raise e1
... except ZeroDivisionError as e2:
...     pass
>>> type(e1)
<type 'DivideByZeroException'>
>>> type(e2)
<type 'exceptions.ZeroDivisionError'>
>>> e2.clsException is e1
True

下麵這段說的是如果Python用戶定義了一個Python類繼承.Net的Exception對象,然後代碼中捕獲到了這個異常,然後用.Net異常信息的讀取方式去訪問異常信息,你將啥也看不到,在下文中異常信息應該是"some message",但是用.net的方式訪問,你只會看到

'Python Exception: MyException'

Python user-defined exceptions get mapped to System.Exception. If non-Python code catches a Python user-defined exception, it will be an instance of System.Exception, and will not be able to access the exception details:

>>> # since "Exception" might be System.Exception after "from System import *"
>>> if "Exception" in globals(): del Exception
>>> class MyException(Exception):
...     def __init__(self, value):
...         self.value = value
...     def __str__(self):
...         return repr(self.value)
>>> try:
...     raise MyException("some message")
... except System.Exception as e:
...     pass
>>> clr.GetClrType(type(e)).FullName
'System.Exception'
>>> e.Message
'Python Exception: MyException'

那麼在.Net中調用IronPython腳本時,如何才能得知腳本運行過程中拋出的Python異常呢?可以使用ScriptEngine.GetService<ExceptionOperations>().GetExceptionMessage方法來獲取

In this case, the non-Python code can use the ScriptEngine.GetService<ExceptionOperations>().GetExceptionMessage DLR Hosting API to get the exception message.

 

Enumerations

下麵是枚舉類型的使用示例

.NET enumeration types are sub-types of System.Enum. The enumeration values of an enumeration type are exposed as class attributes:

print System.AttributeTargets.All # access the value "All"

IronPython also supports using the bit-wise operators with the enumeration values:

也支持 位操作符

>>> import System
>>> System.AttributeTargets.Class | System.AttributeTargets.Method
<enum System.AttributeTargets: Class, Method>

Value types

下麵這一大段說了一大堆,很複雜,機器翻譯困難,看了半天也不知他講什麼,推測:大概是在講,在IronPython中不要試圖修改.Net類型中的值類型,否則會發生很多意想不到的結果

Python expects all mutable values to be represented as a reference type. .NET, on the other hand, introduces the concept of value types which are mostly copied instead of referenced. In particular .NET methods and properties returning a value type will always return a copy.

This can be confusing from a Python programmer’s perspective since a subsequent update to a field of such a value type will occur on the local copy, not within whatever enclosing object originally provided the value type.

While most .NET value types are designed to be immutable, and the .NET design guidelines recommend value tyeps be immutable, this is not enforced by .NET, and so there do exist some .NET valuetype that are mutable. TODO - Example.

For example, take the following C# definitions:

struct Point {
    # Poorly defined struct - structs should be immutable
    public int x;
    public int y;
}

class Line {
    public Point start;
    public Point end;

    public Point Start { get { return start; } }
    public Point End { get { return end; } }
}

If line is an instance of the reference type Line, then a Python programmer may well expect "line.Start.x = 1" to set the x coordinate of the start of that line. In fact the property Start returned a copy of the Point value type and it’s to that copy the update is made:

print line.Start.x    # prints ‘0’
line.Start.x = 1
print line.Start.x    # still prints ‘0’

This behavior is subtle and confusing enough that C# produces a compile-time error if similar code is written (an attempt to modify a field of a value type just returned from a property invocation).

Even worse, when an attempt is made to modify the value type directly via the start field exposed by Line (i.e. “`line.start.x = 1`”), IronPython will still update a local copy of the Point structure. That’s because Python is structured so that “foo.bar” will always produce a useable value: in the case above “line.start” needs to return a full value type which in turn implies a copy.

C#, on the other hand, interprets the entirety of the “`line.start.x = 1`” statement and actually yields a value type reference for the “line.start” part which in turn can be used to set the “x” field in place.

This highlights a difference in semantics between the two languages. In Python “line.start.x = 1” and “foo = line.start; foo.x = 1” are semantically equivalent. In C# that is not necessarily so.

So in summary: a Python programmer making updates to a value type embedded in an object will silently have those updates lost where the same syntax would yield the expected semantics in C#. An update to a value type returned from a .NET property will also appear to succeed will updating a local copy and will not cause an error as it does in the C# world. These two issues could easily become the source of subtle, hard to trace bugs within a large application.

In an effort to prevent the unintended update of local value type copies and at the same time preserve as pythonic and consistent a view of the world as possible, direct updates to value type fields are not allowed by IronPython, and raise a ValueError:

>>> line.start.x = 1 #doctest: +SKIP
Traceback (most recent call last):
   File , line 0, in input##7
ValueError Attempt to update field x on value type Point; value type fields can not be directly modified

This renders value types “mostly” immutable; updates are still possible via instance methods on the value type itself.

 

Proxy types

推測:大概是說在ironPython里不能直接使用C#里的System.MarshalByRefObject實例,但是可以通過非綁定類的實例來調用,這個文檔通篇下來經常使用非綁定類這個詞,一直看不明白到底指的是什麼樣的類。

IronPython cannot directly use System.MarshalByRefObject instances. IronPython uses reflection at runtime to determine how to access an object. However, System.MarshalByRefObject instances do not support reflection.

You can use unbound-class-instance-method syntax to call methods on such proxy objects.

 

Delegates

python方法可以被轉化為委托,傳給事件參數用

Python functions and bound instance methods can be converted to delegates:

>>> from System import EventHandler, EventArgs
>>> def foo(sender, event_args):
...     print event_args
>>> d = EventHandler(foo)
>>> d(None, EventArgs()) #doctest: +ELLIPSIS
<System.EventArgs object at ... [System.EventArgs]>

Variance

ironPython支持委托的參數簽名和事件要求的委托參數簽名不一致,比如下例,使用了Python語法里的“無限無名參數”

IronPython also allows the signature of the Python function or method to be different (though compatible) with the delegate signature. For example, the Python function can use keyword arguments:

>>> def foo(*args):
...     print args
>>> d = EventHandler(foo)
>>> d(None, EventArgs()) #doctest: +ELLIPSIS
(None, <System.EventArgs object at ... [System.EventArgs]>)

本來事件沒有返回值,但是在這裡也支持委托可以寫返回值(這是Python的語法),但實際運作過程中,返回的值會被忽略

If the return type of the delegate is void, IronPython also allows the Python function to return any type of return value, and just ignores the return value:

>>> def foo(*args):
...     return 100 # this return value will get ignored
>>> d = EventHandler(foo)
>>> d(None, EventArgs())

如果委托實際返回的返回值類型和事件要求的返回值類型不符合,那麼解釋器會嘗試強轉後再返回

If the return value is different, IronPython will try to convert it:

>>> def foo(str1, str2):
...     return 100.1 # this return value will get converted to an int
>>> d = System.Comparison[str](foo)
>>> d("hello", "there")
100

TODO - Delegates with out/ref parameters

 

Subclassing .NET types

支持Python類繼承或實現.net的類或介面

Sub-classing of .NET types and interfaces is supported using class. .NET types and interfaces can be used as one of the sub-types in the class construct:

>>> class MyClass(System.Attribute, System.ICloneable, System.IComparable):
...     pass

.Net里不支持多重繼承,但Python里支持這麼乾,但是如下代碼,你支持繼承多個Python類,而不能繼承多個.Net類,不管繼承多少個,其中只能有一個.Net類

.NET does not support multiple inheritance while Python does. IronPython allows using multiple Python classes as subtypes, and also multiple .NET interfaces, but there can only be one .NET class (other than System.Object) in the set of subtypes:

>>> class MyPythonClass1(object): pass
>>> class MyPythonClass2(object): pass
>>> class MyMixedClass(MyPythonClass1, MyPythonClass2, System.Attribute):
...     pass

和.Net一樣,可以利用反射來驗證一個類是否是某個類的子類

Instances of the class do actually inherit from the specified .NET base type. This is important because this means that statically-typed .NET code can access the object using the .NET type. The following snippet uses Reflection to show that the object can be cast to the .NET sub-class:

>>> class MyClass(System.ICloneable):
...     pass
>>> o = MyClass()
>>> import clr
>>> clr.GetClrType(System.ICloneable).IsAssignableFrom(o.GetType())
True

下麵又說Python並沒有真正繼承.Net子類,見類型映射表?  看著好玄乎

Note that the Python class does not really inherit from the .NET sub-class. See type-mapping.

 

Overriding methods

基類方法可以被用Python方法重寫

Base type methods can be overriden by defining a Python method with the same name:

>>> class MyClass(System.ICloneable):
...    def Clone(self):
...        return MyClass()
>>> o = MyClass()
>>> o.Clone() #doctest: +ELLIPSIS
<MyClass object at ...>

推測:下麵意思可能是說,Python語法雖然允許你不真正實現介面方法,編譯上通過,但實際運行的時候會報錯,說實例中並不存在這個方法,所以我們必須要寫出具體實現

IronPython does require you to provide implementations of interface methods in the class declaration. The method lookup is done dynamically when the method is accessed. Here we see that AttributeError is raised if the method is not defined:

>>> class MyClass(System.ICloneable): pass
>>> o = MyClass()
>>> o.Clone()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'Clone'



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 構造器名與類名一致。 1。實例構造器與類(引用類型) 構造器是允許將類型的實力初始化為良好狀態的一種特殊方法。 創建一個引用類型的實例時(類),首先為實例的數據欄位分配記憶體,然後初始化對象的附加欄位(類型對象指針和同步索引快),最後調用類型的實例構造器來設置對象的初始狀態。 new一個類所發生的事: ...
  • 在點擊運行項目時,生成成功。但是頁面沒有彈出來,彈出個提示框,無法連接到 ASP.NET Development Server. 網上我看到說關閉掉防火牆,可是再關掉防火牆後還是不行。但是其他的項目又能跑起來,所以估計是埠號被占用了。 最後的解決方案是: 項目右鍵屬性,在屬性視窗,將使用動態埠號 ...
  • 我個人比較懶,能自動做的事絕不手動做,最近在用ASP.NET Core寫一個項目,過程中會積累一些方便的工具類或框架,分享出來歡迎大家點評。 如果以後有時間的話,我打算寫一個系列的【實現BUG自動檢測】,本文將是第一篇。 如果你使用過ASP.NET Core那麼對依賴註入一定不陌生。 使用流程... ...
  • 在C#.NET的開發中,事件是經常接觸到的概念,比如為按鈕添加點擊事件,並寫入點擊按鈕觸發事件要運行的代碼。不管是ASP.NET還是WinForm等各種形式的應用程式,最經常是為系統生成的事件寫具體代碼。如果要自定義事件呢?有的朋友對於自定義事件感覺比較難理解。最近在開發HoverTreeTop項目 ...
  • C#簡單程式練習 說明:學習之餘溫習幾道經典基礎知識題,將其記錄下來,以供初學者參考。 1,題目:求出0-1000中能被7整除的數,並計算輸出每五個數的和: 運行截圖: 題目2:編寫一個類,其中包含一個排序的方法 Sort(), 當傳入的是一串整數,就按照從小到大的順序輸出,如果傳入的是一個字元串, ...
  • 堆、棧、引用類型、值類型 記憶體分為堆和棧(PS:還有一種是靜態存儲區域 [記憶體分為這三種]),值類型的數據存儲在棧中,引用類型的數據存儲在堆中。 堆、棧: 堆和棧的區別: 棧是編譯期間就分配好的記憶體空間,因此你的代碼中必須就棧的大小有明確的定義;局部值類型變數、值類型參數等都在棧記憶體中。 堆是程式運 ...
  • 本篇和大家分享的是學習Vuejs的總結和調用webapi的一個小示例;快到年底了爭取和大家多分享點東西,希望能對各位有所幫助;本章內容希望大家喜歡,也希望各位多多掃碼支持和推薦謝謝: » Vuejs - 學習大雜燴 » WebApi + Vue.js 示例 下麵一步一個腳印的來分享: » Vuejs ...
  • WEB後臺開發,如果用的是Bootstrap框架,那這個表格神器你一定不要錯過。 官方地址:https://datatables.net/ What?英文不好,沒關係咱有中文的 http://datatables.club/ 不過我還是建議看英文的,因為比較全面雖然訪問的速度慢點,終歸能進的去。閑話 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...