Ваши выражения среза и диапазона также могут быть записаны как:
In [86]: nd15[2:3, 2:3]
Out[86]: array([['e22']], dtype='<U3')
In [87]: nd15[2:3, [2]]
Out[87]: array([['e22']], dtype='<U3')
In [88]: nd15[[2],2:3]
Out[88]: array([['e22']], dtype='<U3')
In [89]: nd15[[2],[2]]
Out[89]: array(['e22'], dtype='<U3')
nd15[2,2]
будет скалярным элементом 'e22'.
Но различия могут быть более ясными, если мы расширим срезы, чтобы получить массив (2,2):
In [97]: nd15[1:3, 2:4]
Out[97]:
array([['e12', 'e13'],
['e22', 'e23']], dtype='<U3')
In [98]: nd15[1:3,[2,3]]
Out[98]:
array([['e12', 'e13'],
['e22', 'e23']], dtype='<U3')
In [99]: nd15[[1,2], 2:4]
Out[99]:
array([['e12', 'e13'],
['e22', 'e23']], dtype='<U3')
In [100]: nd15[[1,2], [2,3]]
Out[100]: array(['e12', 'e23'], dtype='<U3')
Последний - диагональ, (1,2) и (2, 3) элементы.
Out[86]
и Out[97]
- views
, остальные - копии.
На самом деле это может быть очень проблематично, если метод не разработан, чтобы быть переопределенным, и кто-то переопределяет его. В частности, никогда не называйте виртуальный метод от конструктора. Рассмотрите:
class Base {
public Base() {
InitializeComponent();
}
protected virtual void InitializeComponent() {
...
}
}
class Derived : Base {
private Button button1;
public Derived() : base() {
button1 = new Button();
}
protected override void InitializeComponent() {
button1.Text = "I'm gonna throw a null reference exception"
}
}
Производный класс не может знать, что виртуальный вызов метода приведет к своему методу InitializeComponent, называемому, прежде чем одна строка его собственного конструктора работала.
Ayende имеет хорошую обработку того, как работают виртуальные методы:
http://ayende.com/Blog/archive/2007/01/05/HowVirtualMethodsWork.aspx