Sharing

2011年10月31日 星期一

Python 學習手冊第三版筆記 (六)

CH.22 OOP: 大藍圖

  • 可多重繼承,我不一向不太喜歡這個,比較喜歡 Java 的單一繼承,事情有時會簡單一點
  • 每個函式必須加上 self ,我也覺得這個很多餘

CH.23 類別撰碼基礎

  • 和 def 一樣是可執行敘述,執行完後就打包成一個 class 物件,而且是可以動態增加元素
  • >>> class rec: pass    # 一開始裡面什麼都沒有
    
    >>> rec.name = 'Bob'      # 動態增加了一個欄位
    >>> x = rec()
    >>> x.name                      #  x 是 rec 的物件,可以存取到 name
    'Bob'
    >>> x.age                         # 想要存取 age 這個欄位會失敗,因為不存在
    
    Traceback (most recent call last):
      File "< pyshell#20>", line 1, in < module>
        x.age
    AttributeError: rec instance has no attribute 'age'
    >>> rec.age = 3              # 那我們就幫他增加 age 這個欄位吧!
    >>> x.age                        #  可以成功增加
    3
    
    除此之外,我們甚至可以動態增加物件裡面的欄位,不過這就不會影響到原生 Class
    >>> class rec:
     name = 'BoB'
     age = 3
    
    >>> x = rec()
    >>> x.length = 180
    >>> x.length                # 成功增加了 length 這個欄位
    180
    >>> rec.length            # 原生的 rec 仍然沒有這個欄位
    
    Traceback (most recent call last):
      File "< pyshell#34>", line 1, in < module>
        rec.length
    AttributeError: class rec has no attribute 'length'
  • __init__ 是建構子,__del__是解構子,在學C++時有聽過三一律,不知道 Python 有沒有符合這樣的特性
  • 可以利用 __add__、__mul__ 覆蓋運算子

另外函式也是可以輕易的被動態換掉,只要第一個參數是 Self 即可,我想這樣稍微解釋了為什麼他規定要每個函式第一個參數都是 Self,這樣的寫法其實很像我們用 C 在模擬 OOP 時,利用第一個參數來傳送 Instance 的道理是一樣的,所以要說 Python 是很先進的 OOP 的語法,好像又不是那麼一回事,只能說他反璞歸真吧~~

>>> def upperName(self):
 return self.name.upper()

>>> rec.method = upperName
>>> x.method()
'BOB'

CH.24 類別撰碼細節

我突然領悟到為什麼書一開頭有講到 Python 的 Class 類別長的像其它 OOP 語言但其實內裡完全不是那麼一回事。一般 OOP 的 Class 是一種宣告,存在於 ROM 之中,而且在一般狀況下會事先 loading 到 Memory 當中,然後 Instance 是 Class 的實作,每份 Instance 都是獨立的個體、獨立的 Memory,換一種方式來說 Class 的宣告是死的,Instance 是活的。然而 Python 的設計我覺得是一個很偷懶的設計,Class 本身就是一個活著的物件,而每個 Instance 看似是獨立的個體,但其實是障眼法,它其實只做了個身體,然後等你要用到右手的時候,它才做個右手給你,等你要用到左手的時候,它才做個左手給你,不然平常它都是直接偷用 Class 內的東西,所以如果你改了 Class 內的值,也會間接影響到這些 Instance,我看到書裡面這個範例時,快笑翻了,怎麼會有這麼偷懶的語言。

>>> class SharedData:
 spam = 42

>>> x = SharedData()
>>> y = SharedData()
>>> x.spam, y.spam
(42, 42)
>>> SharedData.spam = 99
>>> x.spam, y.spam, SharedData.spam
(99, 99, 99)
>>> x.spam = 88
>>> x.spam, y.spam, SharedData.spam
(88, 99, 99)

而且 Class 的宣告和 Instance 的生成,兩者之間看似很有關係,但這關係很容易被破壞,你除了可以在 Instance 上面加上原來就該有的手、腳外,你高興的話也可以臨時在 Class 上增加個翅膀,也可以臨時在 Instance 上增加個尾巴,然後也可以任意的把眼睛的功能變成透視眼功能,在這樣惡搞之下,Instance 其實可能會長的和 Class 一點也不像,不過幸好的是只能做"加法",而不能做"減法",所以 Instance 至少會保有 Class 所有的欄位及功能。

繼承的部份和 Instance 也很像,關係看似很緊,但其實也是很薄弱,Super class 可以動態亂改,Inheritor 也可以動態亂改,看了半天,我覺得繼承其實也是一種 Instance,只是他是一個有名字、可以方便再利用的 Instance。

Java 中有 Interface,C++ 中有 virtual function,Python 裡面沒有這樣的概念,但在實作上卻可以做的出來,只是如果忘了實作的話要等到要用到時才會發現。(這就是所謂了要吃飯時才發現飯忘了煮嗎?!天呀!真的是偷懶到極點的語言)

>>> class Super:
 def delegate(self):
  self.action()

  
>>> class Provider(Super):
 def action(self):
  print 'in Provider'

  
>>> x = Super()
>>> x.delegate()

Traceback (most recent call last):
  File "< pyshell#75>", line 1, in < module>
    x.delegate()
  File "< pyshell#69>", line 3, in delegate
    self.action()
AttributeError: Super instance has no attribute 'action'
>>> x = Provider()
>>> x.delegate()
in Provider


看到這裡其實也突然讓我發現一個事實,Python 的 method binding 在 def / class 中是不會即時檢查的,也不會事先 linking,而是動態的 linking,所以即使用了一個沒有宣告的函式或是物件,也必須要等到真的有被用到時,才會發現這個事情,但也因為這樣的設計,當你要寫兩個會互相用到的函式(放在不同的模組內),而必須互相 import 時卻不會出事

import modb

def funcA(x):
    if x == 1:
        return 0
    return 1 + modb.funcB(x /2)

class ClassA:
    def getInterClass():
        x = modb.ClassB()
        return x


import moda

def funcB(x):
    if x == 1:
        return 1
    return 1 + moda.funcA(x + 1)

class ClassB:
    def getInnerClass():
        x = moda.ClassA()
        return x



接下來看到 __getitem__ 的應用,書中寫到"買一送一堆",真的是太傳神了,而且我覺得這真的很強大,和__iter__不同的是,反覆器只能繞行一次,而索引運算式則可以一直重覆使用,不過反覆器的用法在寫程式上比較直覺。要解決這樣的問題可以做一個反覆器生成器出來。

__getattr__ 和 __setattr__ 就先跳過不看,太複雜了,竟然是用在實作 private 特性。



CH.25 類別的設計

getattr(X,N) 和 X.__dict__[N] 差異在於,前者也會執行繼承搜尋,但後者不會!

有幾個內建的屬性我覺得還滿重要的,雖然少用但在重要時刻可能會派上用場,特別是 Debug 時

  • 每個類別都有內建 __name__來顯示類別的名字
  • 每個類別都有內建 __bases__ 來顯示其繼承的類別
  • >>> class A: pass
    >>> class B: pass
    >>> class C(A,B): pass
    >>> C.__name__
    'C'
    >>> C.__bases__
    (< class __main__.A at 0x000000000279EF48>, < class __main__.B at 0x000000000279EFA8>)
    >>> C.__bases__[0].__name__
    'A'
    
    
  • __class__ ,每一個實體都可以藉此來辨別他的類別
  • >>> class sample:
     pass
    
    >>> x = sample()
    >>> x.__class__
    < class __main__.sample at 0x000000000279EEE8>
    
  • 每個類別及實體都有 __dict__ 來表示其擁有的屬性,但不包含繼承來的
  • 可以使用 dir 函式來找出所有的屬性,包括自動繼承的部份
  • >>> class C(A,B): pass
    >>> C.__dict__
    {'__module__': '__main__', '__doc__': None}
    >>> dir(C)
    ['__doc__', '__module__']
    >>> x = C()
    >>> x.__dict__
    {}
    >>> dir(x)
    ['__doc__', '__module__']
    
無綁束類別方法物件:必須要明確提供實體物件作為第一個引數 綁束實體方法物件: self + 函式配對,不必再另外傳入 self 兩種除了在使用方法上不一樣外,其它內建的屬性幾乎都一樣,只有 im_self 不同

>>> class Spam():
 def doit(): pass
>>> Spam.doit
< unbound method Spam.doit>
>>> x = Spam()
>>> x.doit
< bound method Spam.doit of <__main__.Spam instance at 0x00000000027A3CC8>>
>>> x.doit.__dict__
{}
>>> Spam.doit.__dict__
{}
>>> dir(x.doit)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'im_class', 'im_func', 'im_self']
>>> dir(Spam.doit)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'im_class', 'im_func', 'im_self']

>>> x.doit.im_self
<__main__.Spam instance at 0x00000000027A3188>
>>> Spam.doit.im_self

__doc__ 可以取得註解,註解必須寫下類別或是函式宣告的下一行



CH.26 高等類別議題
類別內以 "__" 開頭的屬性會被重新命名成 _[Classname]__[原始名稱],不論是一般變數或是函式,但在類別內的宣告時仍然可以用原始名稱來存取,但我覺得 Python 的作者發明這樣的東西其實也不是真的私有化,如果真的要解決書中的問題,可以發明關鍵字 "private" ,不是更乾脆?! 再來是靜態方法及類別方法之間的轉換可以靠 staticmethod 及 classmethod 我覺得也滿醜的,為什麼不用 static 這樣的關鍵字來處理? 更何況打從一開始,我就覺得 Python 是給懶人用的,根本不需要私有化及靜態方法,硬加上這些功能有點四不像。
__slots__ 可能會造成實體沒有 __dict__,以下是一個例子,不但影響了實體,其實連類別的 __dict__ 也產生了變化
>>> class limiter(object):
 __slots__  = ['age', 'name']
>>> x = limiter()
>>> limiter.__dict__
< dictproxy object at 0x00000000027A9108>
>>> x.__dict__

Traceback (most recent call last):
  File "< pyshell#169>", line 1, in < module>
    x.__dict__
AttributeError: 'limiter' object has no attribute '__dict__'
>>> dir(limiter)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name']
>>> dir(x)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name']
靜態方法、類別方法、一般方法的定義都不太一樣,尤其是"類別方法" ,被宣告成靜態方法後,不管是透過類別或是透過實體去呼叫,都只是一般的函式而己,不需要管是否有綁定,再來是實體內的函式都是有被綁定,透過類別的函式,如果有宣告 classmethod ,那就變成綁定的函式,但不管呼叫的是類別或是實體,都是綁定 class。
class Multi:
    def imeth(self, x):
        print self, x
    def smeth(x):
        print x
    def cmeth(cls, x):
        print cls, x
    smeth = staticmethod(smeth)
    cmeth = classmethod(cmeth)

>>> Multi.imeth
< unbound method Multi.imeth>                         # 非綁定
>>> Multi.smeth
< function smeth at 0x0000000002773E48>     # 一般函式
>>> Multi.cmeth
< bound method classobj.cmeth of < class __main__.Multi at 0x000000000276E6A8>>   # 綁定 class

>>> y = Multi()
>>> y.imeth
< bound method Multi.imeth of <__main__.Multi instance at 0x0000000002774D88>>   # 綁定 instance
>>> y.smeth
< function smeth at 0x0000000002773E48>   
>>> y.cmeth
< bound method classobj.cmeth of < class __main__.Multi at 0x000000000276E6A8>>   # 綁定 class

>>> Multi.imeth.im_self
>>> Multi.smeth.im_self

Traceback (most recent call last):
  File "< pyshell#297>", line 1, in < module>
    Multi.smeth.im_self
AttributeError: 'function' object has no attribute 'im_self'
>>> Multi.cmeth.im_self
< class __main__.Multi at 0x000000000270E6A8>


>>> y.imeth.im_self
<__main__.Multi instance at 0x0000000002713D08>
>>> y.smeth.im_self

Traceback (most recent call last):
  File "< pyshell#293>", line 1, in < module>
    y.smeth.im_self
AttributeError: 'function' object has no attribute 'im_self'
>>> y.cmeth.im_self
< class __main__.Multi at 0x000000000270E6A8>


2011年10月27日 星期四

Ubuntu 上增加新使用者


pjack@ubuntu64-33-7:~$ sudo adduser wistor
[sudo] password for pjack:
Adding user `wistor' ...
Adding new group `wistor' (1001) ...
Adding new user `wistor' (1001) with group `wistor' ...
Creating home directory `/home/wistor' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for wistor
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] y
pjack@ubuntu64-33-7:~$ sudo adduser wistor admin
Adding user `wistor' to group `admin' ...
Adding user wistor to group admin
Done.



如果在執行 sudo 時不想需要密碼,要在 /etc/sudoers.d 內新增檔案, 內容加上 NOPASSWD

root@ubuntu1104-64-5:/etc/sudoers.d$ ls
pjack  README  www-data
root@ubuntu1104-64-5:/etc/sudoers.d$ cat pjack
pjack   ALL=(ALL:ALL) NOPASSWD: ALL

Install GUI on Ubuntu Server 11.10 and Remote Control from Windows



Solution 1: Install GNOME desktop

                 sudo apt-get install ubuntu-desktop

Solution 2: install GNOME desktop without recommend software

                 sudo apt-get install --no-install-recommends ubuntu-desktop

                 [這個怪怪的.. 會開不了機, 卡在 PulseAudio configured for per-user sessions]

Solution 3: install light weight desktop xfce

                 sudo apt-get install xubuntu-desktop

Solution 4: install KDE desktop

                 sudo apt-get install kubuntu-desktop

最後再安裝 xrdp, 就大功告成啦~

install xrdp

補: 透過 xrdp , 按 d 的時候, 會把所有的視窗小

Now in order to get the proper keyboard map and theme in GNOME, you need to make a modification:
Open gconf-editor either by typing that in a console, or in the Alt+F2 window.
Inside gconf-editor, navigate to /apps/gnome_settings_daemon/plugins/keyboard and set “active” to false.
or do the following steps
gconf-editor ->app->metacity->global_keybindings
Change the assigned keystroke for show_desktop from "d" to "d" or "d" or "disabled"
But this changes are only for the active user.
To set this option for all Users do the following:
Right click on "show_desktop" and choose  set Mandatory or set it as default. You can check this option if you choose File --> New Mandatory Window. See also this page for more informations.
補: 透過 xrdp, 有些 icon 會不見, 也無法 logout 我後來改用 gnome-shell 就沒問題

sudo apt-get install gnome-shell
sudo nano /etc/lightdm/lightdm.conf             # 把 user-session=ubuntu-2d

2011年10月26日 星期三

Ubuntu 11.10 安裝 Sun Java 6 JDK/JRE


手動安裝JDK

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jdk

手動安裝JRE

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-fonts

2012-03-18 補:
後來發現這個 ppa 沒有再更新,就一直停在 1.6.26 版本,只好再找別的方式,網路上有人寫好更新的 script

http://blog.flexion.org/2012/01/16/install-sun-java-6-jre-jdk-from-deb-packages/

wget https://raw.github.com/flexiondotorg/oab-java6/master/oab-java6.sh -O oab-java6.sh
chmod +x oab-java6.sh
sudo ./oab-java6.sh

Python 學習手冊第三版筆記 (五)


CH.18 模組: 大藍圖

網路上 Python Standard library 真是多的誇張呀~ 看起來還是要花一點時間瀏覽一下基本的東西,然後剩下的只能邊用邊查了! 這讓我覺得 Python 真是好物,library 很齊全而且都有統一整理起來。


CH.19 模組撰碼基礎

Programming Python
Free online Python Programming Tutorial

使用模組幾個注意的點

  • 匯入只會發生一次, 這也順便解決部份 recursive import 的問題, 而 reload 可強制重新 import
  • 沒有必要就少用 from,會模糊掉模組空間
  • 模組程式碼絕無法看見其他模組內的名稱,除非刻意予以匯入,P.402 的例子是在說明這點,如果我把 modb 加一行,會發現 modb 內的 X 值改變了,原因是我們強迫在 modb 內複製一份 moda 的 X,但同時要強調的是這只是複製品,所以 moda.X 最終結果會是 99 ,而本地的 X 絕對不會受到影響

    X = 11
    import moda
    from moda import X   # 強迫把 X import 進來且複製一份
    moda.f()
    print X, moda.X
    

    >>> 
    loading moda...
    loading moda finish 
    88 99
    

CH.20 模組套件

套件的匯入是利用指定目錄路徑,這一點很像 Java 的設計,大家可以同時寫自己的 utility.py 而不會彼此衝突到

CH.21 高等模組議題

__name__ 預設是 '__main__',但如果檔案是被匯入的,則會被改成其模組名稱,用途之一是把自我測試呼叫包放在檔案內,被人匯入時又不會被執行,另一個可能會用到的是 __file__

if __name__ == '__main__':
    test()    # test code


import as 延伸功能,這個有點像是 alias 功能

比較這兩種寫法,前者在使用 function 時必須把全部的名字寫出來,後者則不需要
import sound.effects.echo
sound.effects.echo.echofilter(...)

from sound.effects import echo
echo.echofilter(...)



2011年10月25日 星期二

Python 學習手冊第三版筆記 (四)

CH.15 函式基礎

要注意的概念有幾點
  • def 是可執行的程式碼,它並不是宣告而已,也不是 Macro,它其實做的事情是把一段程式碼打包成一個函式物件,然後傳給函式變數,之後我們可以透過這個函式變數來執行這段程式碼,所以他甚至是可以動態決定這段程式碼要長成什麼樣子
if test:
    def func():
        ...
else:
    def func():
       ....
...
func()

CH.16 範圍和引數

區域變數和廣域變數的簵圍的概念在 C 當中並不陌生, 不過在操作上有一些要注意的部份,因為python不需要宣告 variable 就可以開始使用,所以一但你在函式中把一個值指定給一個變數後,他就會生出一個 local variable,以下面這個例子為例,對 C programmer 來說,應該會印出 100,但在 python 來說,它其實已經建立了 local variable,所以 function 中存取的其實是 local variable,而不是 global variable,乍看之下會覺得有問題,但理解 python 是怎麼運作之後就不會覺得奇怪了

>>> def local():
 var = 100
>>> var = 0
>>> local()
>>> print var
0

如果一定要改變 global variable,就必須加上 global 這個關鍵字
>>> def local():
 global var
 var = 100
>>> var = 0
>>> local()
>>> print var
100

如果只是單獨要讀取 global variable,不一定要加上 global 關鍵字,只要你沒有宣告過同樣名字的 local variable ,它就會自動去上一層的區域找尋這個變數,這個還算顯然,和 C 沒什麼不同

>>> def local():
 print var
>>> var = 100
>>> local()
100

不過我又改寫了 local 這個函式,一開始不太明白為什麼會有 error 訊息,到後來才明白一件事,我們不能把 python 的函式看成逐行執行的 script,而必須把它看成一個整體的東西,一但函式打包起來,它就會知道裡面有一個叫 var 的 local variable,所以其實第一行要印 var 時就會出問題,它會認為 var 還沒給過值是不能印的


>>> def local():
 print var                     #  我覺得應該要印出 global variable
 var = 100                    #  生成  local variable
 print var                     #  我覺得應該要印出  local variable
>>> var = 100
>>> local()

Traceback (most recent call last):
  File "", line 1, in 
    local()
  File "", line 2, in local
    print var
UnboundLocalError: local variable 'var' referenced before assignment
>>> 

工廠函式以前在 C 是個禁忌,因為一般都是病毒型的程式碼才會動態生成函式,聽說會自我變種的病毒也都是利用了類似的技巧,想不到在 Python 中可以輕易的實作出來。

書中的這個例子,說明了如果要大量製造函式時,引數必須要以預設值傳進新函式中,否則製造出來的函式都會是長的一樣的,對於這個例子我看了很久,最後我對於他的解讀是新函式中的 i 因為找不到對應的 local variable ,所以會被強迫指向 makeActions 中的 i,也就是說所有新生成的函式都會指向同一個 i ,才會造成執行結果都一樣。書中用 "實質上都是記住相同之值" 來描述這件事其實讓我一開始無法理解,如果用 "指標指向同一個變數" 來講,可能就會更清楚。

>>> def makeActions():
    acts = []
    for i in range(5):
        acts.append(lambda x: i ** x)
    return acts

>>> acts = makeActions()
>>> acts[0](2)
16
>>> acts[1](2)
16

記得在 C 當中在處理任意引數是很麻煩的,我曾經想要做一件事,就是把 funcA 的任意引數再傳進 funcB,結果我花了很多時間研究有沒有辦法做到,發現似乎沒有解,到現在我仍然不知道要怎麼做,但在 Python 當中這件事真的是簡單到不行,不得不佩服 Python 設計者的巧思

int sum(int count, ...)
{
   va_list ap;
   int j;
   int tot = 0;
   va_start(ap, count);
   tot = va_arg(ap, int);                         /* 把第一個取出來 */
   va_end(ap);

   return tot + sum(count - 1, ...?? )      /* 想要用遞迴的方式算出剩下的加總,但這裡不知道要填什麼  */
}

def sum(*args):
    len_of_args = len(args)
    if len_of_args == 1:
        return args[0]
    if len_of_args == 0:
        return 0
    return sum(*args[0:len_of_args/2]) + sum(*args[len_of_args/2:])   /* 輕易的把變動參數傳給下一個函式 */

CH.17 高等函式議題

在第十六章看到 lambda 時還無法理解為什麼要有這個東西,覺得它的功用和 function 沒什麼兩樣,但看到第十七章的說明後,這讓我想到 Java 裡面有 Anonymous inner classes,感覺有異曲同工之妙,同樣都是為了省下宣告新的 class ,把 class 及使用 function/class 的人緊緊的綁在一起。

button1.addActionListener(
         new java.awt.event.ActionListener()
         {
            public void actionPerformed(java.awt.event.ActionEvent e)
            {
               // do something
            }
         }
      );

apply, filter, reduce 跳過不看

list comprehension 的語法要記熟!

[expression for target1 in sequence1 [if condition1]
for target2 in sequence2 [if condition2]
for target3 in sequence3 [if condition3] ... ]

然後記下一個二維矩陣的用法,和一般用法不同

[[M[row][col] * N[row][col] for col in range(3)] for row in range(3)]

2012.03.24 補:
因為實在太重要了, 但又常忘記要怎麼用, 留幾個 sample link
http://docs.python.org/reference/expressions.html?highlight=list%20comprehension#list-displays
http://www.secnetix.de/olli/Python/list_comprehensions.hawk
http://docs.python.org/tutorial/datastructures.html#list-comprehensions
http://www.bogotobogo.com/python/python_list_comprehension.html



可變更預設引數在函式呼叫之間會保留其狀態,這一點我真的覺得太奇怪了,真的很容易造成陷阱,一般來說程式設計者預設應該不是想要這種功能才對呀~ 早就己經習慣固定的參數輸入值會得到固定的結果的我,實在不太能接受這點,這真的要好好記一下

>>> def saver (x=[]):
 x.append(1)
 print x
>>> saver()
[1]
>>> saver()
[1, 1]

2011年10月24日 星期一

Python 學習手冊第三版筆記 (三)


Ch.10 Python 敘述簡介

None

Ch.11 指定敘述、運算式、以及列印

Python 會建立臨時之 tuple,以儲存右側變數原始之值,所以在交換兩變數之值,就很方便,不過我做了個小實驗,刻意的讓它交換兩次,原以為會有交換兩次的狀況,但發現沒有,也找不到合理的解釋來滿足第三個及第四個例子,所以目前還是不太清楚它是怎麼運作的,總之,少寫這樣會讓人看不懂的式子吧!

>>> A = 1
>>> B = 2
>>> A, B = B, A
>>> A, B
(2, 1)
>>> A, B, C = 1, 2, 3
>>> A, B, C
(1, 2, 3)
>>> A, B, C = B, C, A = C, A, B
>>> A, B, C
(2, 3, 1)
>>> A1, B1, C1 = 1, 2, 3
>>> A2, B2, C2 = 4, 5, 6
>>> A1, B1, C1 = B1, C1, A1 = A2, B2, C2
>>> A1, B1, C1
(6, 4, 5)
>>> A1, B1, C1 = 1, 2, 3
>>> A2, B2, C2 = 4, 5, 6
>>> A3, B3, C3 = 7, 8, 9
>>> A1, B1, C1 = A2, B2, C2 = A3, B3, C3
>>> A1, B1, C1
(7, 8, 9)

  • 單一底線的名稱 (_X) 不會被 from module import * 匯入,可以用來分辨這是公用函式或是私用函式

  • 前後有雙底線的名稱 (__X__) 是系統定義名詞,也不要隨意使用

  • 以兩底線開頭、但結尾沒有雙底線 (__X) 是類別之區域變數

  • 可利用 sys.stdout = open(xxxx) 來重導向輸出串流

  • 可以用 print >> file, [...] 來印東西到檔案中

  • 如果物件有定義 write 函式,也可以用 print >> object, [...] 來輸入東西


  • Ch.12 if 測試

  • X or Y or ... : Python 會由左至右求算運算元物件,然後傳回第一個為真者,不然就就傳回最後一個

  • X and Y and ... : 傳回第一個為假者,不然就傳回最後一個

  • if / else 三元運算式,有幾種表示法


  • if X:
        A = Y
    else:
        A = Z
    
    A = Y if X else Z
    
    A = ((X and Y) or Z)
    
    A = [Z, Y][bool(X)]
    
    

    如果用布林值 (or 、and) 來做運算,要注意的是可能不會執行所有的運算式,這和 C 也是一樣的

    Ch.13 while 與 for 迴圈


    和 C 不太一樣的部份有兩個

    1. 多了  pass 語法,代表的是什麼事也不做, 不過就和書上寫的一樣,真的有用的程式碼似乎都不太會用到這個語法, 比較像是我們在開發過程中, 有時候會寫上註解 /* TODO:  */ ,留下空白的內容,計劃之後再補上,這個時候可以先用 pass 來代替這個部份,所以目前我想像中的可能性是我寫完程式碼後可以回頭檢查有沒有 "pass" 留在程式碼中,如果有的話就表示我有東西忘了補。
    2. .
    3. 可以和 else 做搭配。以前寫 C 時, 會遇到一些 case, 在 for 迴圈之後,判斷 counter 是否有執行到最後,如果有才會觸發某些事,如果是中途就中斷的,就會跳過,我覺得這個有些相似,可以強化彼此的關係,讓可讀性更強。不過 while/for 和 else 搭配, 看起來真的很不習慣

    C 的寫法
    while (x > 1)
    {
           if ((y % x) == 0) 
           {
              printf(" y has factor %d\n", x);
              break;
           }
           x--           
    }
    
    if (x == 1)
         printf("y is prime\n");
    


    Python 的寫法
    while x > 1:
        if y % x == 0:
            print 'y has facter %d' % x
            break;
        x = x - 1
    else:
        print 'y is prime'
    
    

    過去用 C 寫遞迴的邏輯,是有一個 counter 時,而且可以清楚有上限時,就用 for loop,否則就用 while loop,但在 Python 當中它把 for loop 更抽像化一層,如果是在一個集合中想要輪流對每一個子元素操作時,就用 for loop,否則用 while loop ,用 for loop 的好處是有些物件會定義反覆器 (iterator? ),幫助更快速的存取子元素,而且可以在Python虛擬機器中做最佳化處理


    D = {'a':1, 'b':2, 'c':3}
    # 不使用反覆器
    for key in D.keys() :
        print key, D[key]
    
    # 使用 Dictionary 內建的反覆器
    for key in D
        print key, D[key]
    
    這兩種方式可以達到一樣的結果, 但效能卻不一樣, 後者會更好
    
    

    zip: 把兩個序列平行串接起來, 當引數長度不同時,zip 會以最短序列為主來截斷其它的序列,拿來建構辭典很方便

    >>> S1 = 'abc'
    >>> S2 = 'xyz123'
    >>> zip(S1, S2)
    [('a', 'x'), ('b', 'y'), ('c', 'z')]
    
    

    map: 和 zip 類似, 但會以最長序列為主來做 mapping

    >>> map(None, S1, S2)
    [('a', 'x'), ('b', 'y'), ('c', 'z'), (None, '1'), (None, '2'), (None, '3')]
    


    如果要施加一種運算至集合中的每個項目, 也可以利用 List comprehension
    >>> L = [1,2,3,4,5]
    
    # 利用 for loop
    >>> for i in range(5):
     L[i] += 10
    >>> L
    [11, 12, 13, 14, 15]
    
    # 利用 List comprehension 做一樣的事
    
    >>> L = [x+10 for x in L]
    >>> L
    [21, 22, 23, 24, 25]
    
    

    更複雜的 List comprehension

    >>> [x+y for x in 'abc' for y in 'lmn']
    ['al', 'am', 'an', 'bl', 'bm', 'bn', 'cl', 'cm', 'cn']
    

    Ch.14 說明文件插曲

    無特別紀錄

    Python 學習手冊第三版筆記 (二)

    CH.4 Python 物作型態簡介

    第一次看到這段程式碼時,就笑倒在地上,好可愛的語法呀!
    >>> x = 'spam'
    >>> x * 8
    'spamspamspamspamspamspamspamspam'
    

  • dir 函式,可以傳回指定物件可用之所有屬性串列,包括了繼承來的




  • help 函式,配合 PyDoc 從物件中抽取出說明文件




  • re 的模組內,可以做 regular expression 的搜尋及比對




  • sorted 函式,是新的內建函式,可以用來把字典轉成序列並且排序




  • list / dict 不能直接用 "+",必須要用 append,但 Tuple 可以用 "+" 來合併物件





  • CH.5 數字

  • 底板除法 // ,小數部份一定會被去掉





  • >>> 1/2
    0
    >>> 1//2
    0
    >>> 1.0/2
    0.5
    >>> 1.0 // 2
    0.0
    

  • python 中以 0 開頭的數字都會預設是 8 進位





  • CH.6 動態定型簡介

  • copy 是淺層複製,deepcopy 是深層複製




  • is 是比較實作參照值的指標,而 == 是比較值





  • CH.7 字串

  • S[:] 是取出從頭到尾的項目,等於進行複製一份



  • S[I:J:K],也就是取出 S 之中,從 I 到 J-1、間隔K的所有項目



  • S[::-1] ,從右走至左,效果就是逆轉序列



  • ord(S) 會印出 S 的 ASCII 代碼,S 是單一字元



  • 字串格式:$[(name)][flags][width][.precesion] code



  • 辭典式字串格式 ex: "%(key1)d %(key2)s" % {"key1":1, "key2":"spam"}






  • CH.8 串列和辭典

  • 索引和切片都是直接修改主體,而不是產生新串列,這一點和字串不同

  • L[1:2] = [] 其實是刪除運算



  • 辭典並非序列,它是沒有順序的,所以不能用 index 來用 for 敘述予以繞行,但可以用反覆器來拿到所有的成員





  • CH.9 Tuple、檔案、以及其他一切

  • 開啟 file 之後,有 readline 及 readlines 兩個 API,一個是回傳字串,一個是回傳字串陣列


  • eval() 這個內建函式可以把字串視為可執行程式碼


  • pickle 可以讓我們直接在檔案中儲存任何 Python 物件


  • F = open('datafile.txt', 'w')
    import pickle
    pickle.dump(D, F)
    F.close()
    
    F = open('datafile.txt')
    E = pickle.load(F)
    

  • 另一種工作 struct 模組知道如何將物件打包成二進位資料


  • >>> F = open('data.bin', 'wb')
    >>> import struct
    >>> bytes = struct.pack('>i4sh', 7, 'spam', 8)
    >>> bytes
    '\x00\x00\x00\x07spam\x00\x08'
    >>> F.write(bytes)
    >>> F.close()
    >>> 
    >>> F = open('data.bin', 'rb')
    >>> data = F.read()
    >>> data
    '\x00\x00\x00\x07spam\x00\x08'
    >>> values = struct.unpack('>i4sh', data)
    >>> values
    

  • == 運算子測試值的相等性。但 is 是測試物件本體,測試兩者是否是相同物件,或是 A 是 B 的其中一種


  • >>> L1 = [1, ('a', 3)]
    >>> L2 = [1, ('a', 3)]
    >>> L1 == L2, L1 is L2
    (True, False)
    

  • 循環式資料結構會印出 [...] 來代表


  • >>> L = ['grail']
    >>> L.append(L)
    >>> L
    ['grail', [...]]
    


    Python 學習手冊第三版筆記 (一)

    CH.1 簡介

    這篇學習筆記是回頭再看一次才寫下來的,第一章的簡介我覺得作者這段描述的很好: Python 是一種混合體,其置於傳統描述語言 (Tcl、Perl) 以及系統開發語言 ( C、C++、Java) 之間。

    CH.2 Python 如何執行程式



    CH.3 如何執行程式

    其它 Python 程式來啟動 (例如,exefile、os.popen、os.system) ,必須參考 Programming Python (O'Reilly)

    2011年10月20日 星期四

    Install Ceph 0.37


    配合 ubuntu oneiric (11.10) release, Ceph 也 release 0.37, 在安裝上更方便了, 然後 library 也更齊全, 首先參考他新的 document

    http://ceph.newdream.net/docs/latest/ops/install/mkcephfs/#installing-the-packages

    wget -q -O- https://raw.github.com/NewDreamNetwork/ceph/master/keys/release.asc | sudo apt-key add -
    
    sudo tee /etc/apt/sources.list.d/ceph.list << EOF <="" apt-get="" ceph.newdream.net="" ceph="" deb-src="" deb="" debian="" eof="" http:="" install="" main="" natty="" pre="" sudo="" update="">
    
    
    The following packages have unmet dependencies:
     ceph : Depends: libcrypto++8 but it is not installable
            Depends: ceph-common but it is not going to be installed
            Recommends: ceph-fuse but it is not going to be installed
            Recommends: libcephfs1 but it is not going to be installed
            Recommends: librados2 but it is not going to be installed
            Recommends: librbd1 but it is not going to be installed
            Recommends: btrfs-tools but it is not going to be installed
    
    接下來設定好 /etc/ceph/ceph.conf, (請按照網站上的設定方法, 因為舊的設定檔無法使用) , 1mon + 1mds + 2osd
    [global]
            auth supported = cephx
            keyring = /etc/ceph/$name.keyring
            log file = /var/log/ceph/$name.log
            log_to_syslog = true        ; uncomment this line to log to syslog
            pid file = /var/run/ceph/$name.pid
    
    [mon]
            mon data = /srv/mon.$id
    
    [mon.a]
            host = ubuntu1104-64-5
            mon addr = 172.16.33.5:6789
    
    [mds]
    
    [mds.a]
            host = ubuntu1104-64-5
    
    [osd]
            osd data = /srv/osd.$id
            osd journal = /srv/osd.$id.journal
            osd journal size = 1000 ; journal size, in megabytes
    
    [osd.0]
            host = ubuntu1104-64-5
            btrfs devs = /dev/mapper/ubuntu1104--64--5-lvol0
    
    
    [osd.1]
            host = ubuntu1104-64-6
            btrfs devs = /dev/mapper/ubuntu1104--64--6-lvol0
    
    
    
    把 master 的 public key import 到其它台
    root@ubuntu1104-64-5:~$ ssh-copy-id -i /root/.ssh/id_dsa.pub root@172.16.33.6
    root@ubuntu1104-64-5:~$ ssh-copy-id -i /root/.ssh/id_dsa.pub root@172.16.33.7
    root@ubuntu1104-64-5:~$ mkdir /var/log/ceph # 把 log folder 先建出來
    
    # 把 file system 建立起來
    
    root@ubuntu1104-64-5:/etc/ceph$ mkcephfs -a -c /etc/ceph/ceph.conf --mkbtrfs
    
    # 把 service 啟動起來
    
    root@ubuntu1104-64-5:/etc/ceph$ service ceph -a start
    === mon.a ===
    Starting Ceph mon.a on ubuntu1104-64-5...
    starting mon.a rank 0 at 172.16.33.5:6789/0 mon_data /srv/mon.a fsid cbb32d58-ceb8-7379-e10e-fc5ad51
    865e3
    === mds.a ===
    Starting Ceph mds.a on ubuntu1104-64-5...
    starting mds.a at 0.0.0.0:6800/1124
    === osd.0 ===
    Mounting Btrfs on ubuntu1104-64-5:/srv/osd.0
    Scanning for Btrfs filesystems
    Starting Ceph osd.0 on ubuntu1104-64-5...
    starting osd.0 at 0.0.0.0:6801/1198 osd_data /srv/osd.0 /srv/osd.0.journal
    === osd.1 ===
    Mounting Btrfs on ubuntu1104-64-6:/srv/osd.1
    Scanning for Btrfs filesystems
    Starting Ceph osd.1 on ubuntu1104-64-6...
    starting osd.1 at 0.0.0.0:6800/19846 osd_data /srv/osd.1 /srv/osd.1.journal
    
    
    authtool 的名字改成 ceph-authtool
    root@ubuntu1104-64-5:/etc/ceph$ ceph -s
    2011-10-20 14:39:54.756735    pg v64: 396 pgs: 396 active+clean; 24 KB data, 4672 KB used, 395 GB / 400 GB avail
    2011-10-20 14:39:54.757492   mds e4: 1/1/1 up {0=a=up:active}
    2011-10-20 14:39:54.757512   osd e4: 2 osds: 2 up, 2 in
    2011-10-20 14:39:54.757541   log 2011-10-20 14:39:55.081612 osd.1 172.16.33.6:6800/19846 102 : [INF] 1.5e scrub ok
    2011-10-20 14:39:54.757582   mon e1: 1 mons at {a=172.16.33.5:6789/0}
    
    root@ubuntu1104-64-5:/etc/ceph$ ceph auth list
    2011-10-20 14:40:10.586279 mon <- [auth,list]
    2011-10-20 14:40:10.586960 mon.0 -> 'installed auth entries:
    mon.
            key: AQDfwJ9OkCqOJRAAB5cXyb6EzUrMbCOL1xGVUw==
    mds.a
            key: AQDfwJ9OyMIiIBAAh07TCA6SAkNKixVYoyJGvA==
            caps: [mds] allow
            caps: [mon] allow rwx
            caps: [osd] allow *
    osd.0
            key: AQDcwJ9OYP7LKhAAhfO7c11l+U5KAGAP+8kVqw==
            caps: [mon] allow rwx
            caps: [osd] allow *
    osd.1
            key: AQDnwJ9OOKCqBBAA/oPp6Z1yg+WjuTAutZHT7g==
            caps: [mon] allow rwx
            caps: [osd] allow *
    client.admin
            key: AQDfwJ9O8AVZJBAAWe9LfeOYUIP7GauVU1Mi5A==
            caps: [mds] allow
            caps: [mon] allow *
            caps: [osd] allow *
    ' (0)
    
    

    2011年10月19日 星期三

    Why cannot remove logical volume?


    今天想要把兩個 volume 合併起來, 所以計劃把 volume 1 砍掉, 然後 extend volume0, 但想不到竟然無法砍成功

    這個是原本的狀態
    root@ubuntu1104-64-6:/etc/ceph$ lvscan
      /dev/dm-3: read failed after 0 of 4096 at 0: Input/output error
      ACTIVE            '/dev/ubuntu1104-64-6/root' [45.86 GiB] inherit
      ACTIVE            '/dev/ubuntu1104-64-6/swap_1' [23.99 GiB] inherit
      ACTIVE            '/dev/ubuntu1104-64-6/lvol0' [50.00 GiB] inherit
      ACTIVE            '/dev/ubuntu1104-64-6/lvol1' [50.00 GiB] inherit
    

    先試了一下另一台 Server, 很順利的砍掉, 完全沒有問題
    root@ubuntu1104-64-5:/etc/ceph$ lvremove /dev/ubuntu1104-64-5/lvol2
    Do you really want to remove active logical volume lvol2? [y/n]: y
      Logical volume "lvol2" successfully removed
    

    試一下網路上的教學, 先把 volume 設成 inactive, 但想不到竟然也失敗!
    root@ubuntu1104-64-6:/etc/ceph$ lvchange -an -v /dev/ubuntu1104-64-6/lvol1
        Using logical volume(s) on command line
      /dev/dm-3: read failed after 0 of 4096 at 0: Input/output error
        Deactivating logical volume "lvol1"
        Found volume group "ubuntu1104-64-6"
      LV ubuntu1104-64-6/lvol1 in use: not deactivating
    

    第二招是使用更底層的指令, dmsetup 來砍, 也失敗!
    root@ubuntu1104-64-6:/etc/ceph$ dmsetup remove /dev/ubuntu1104-64-6/lvol1
    device-mapper: remove ioctl failed: Device or resource busy
    Command failed
    


    用 dmsetup 看一下他的狀況, Open = 1 , 想了一下可能是有某個 process 還在用這個 volume
    root@ubuntu1104-64-6:/etc/ceph$ dmsetup info -c /dev/ubuntu1104-64-6/lvol1
    Name                    Maj Min Stat Open Targ Event  UUID                                          
    ubuntu1104--64--6-lvol1 251   3 L--w    1    1      0 LVM-j8BFBw1hbMLXLb4PCFPraeHAaodggpk2S8Wp56e6pUM8peKY22w0V5QMy8hSn3aA
    

    用 lsof 來看一下有沒有 process 在使用, 啥! 也沒有@@
    root@ubuntu1104-64-6:/etc/ceph$ lsof /dev/ubuntu1104-64-6/lvol1
    

    突然想到前兩天有玩 iscsi, 該不會我有 export 出去吧.. 咦.. 好像是喔!
    root@ubuntu1104-64-6:/etc/iet$ /etc/init.d/open-iscsi stop
     * Disconnecting iSCSI targets
       ...done.
     * Stopping iSCSI initiator service
       ...done.
    root@ubuntu1104-64-6:/etc/iet$ /etc/init.d/iscsitarget stop
     * Removing iSCSI enterprise target devices:
       ...done.
     * Removing iSCSI enterprise target modules:
       ...done.
    

    把 iscsi 停下來後, 總算砍成功啦!
    root@ubuntu1104-64-6:/etc/iet$ lvremove /dev/ubuntu1104-64-6/lvol1
      /dev/dm-3: read failed after 0 of 4096 at 0: Input/output error
    Do you really want to remove active logical volume lvol1? [y/n]: y
      Logical volume "lvol1" successfully removed
    


    把 vol0 extend 成 200G, 任務完成!
    root@ubuntu1104-64-6:/etc/iet$ lvresize -L +150G /dev/ubuntu1104-64-6/lvol0
      Extending logical volume lvol0 to 200.00 GiB
      Logical volume lvol0 successfully resized
    root@ubuntu1104-64-6:/etc/iet$ lvscan
      ACTIVE            '/dev/ubuntu1104-64-6/root' [45.86 GiB] inherit
      ACTIVE            '/dev/ubuntu1104-64-6/swap_1' [23.99 GiB] inherit
      ACTIVE            '/dev/ubuntu1104-64-6/lvol0' [200.00 GiB] inherit
    
    

    2011年10月18日 星期二

    How to see Python code in Source Insight



    資訊是從 http://wiki.python.org/moin/PythonEditors 找到的

    1. 下載 Source Insight 的一個CLF文件
    http://www.sourceinsight.com/public/languages/Python.CLF

    2. 打開 Source Insight, 選擇options->Preferences->Language->Import->將剛剛的clf文件導入進來



    3. options->Document options-> Add Type -> 輸入 Python

    4. 接下來就會多一個 Python 的 Document Type, 選擇它之後, 要把其它的東西都設定好
        a. Language => Python Language
        b. File filter => *.py
        c. turn on "Include when adding to projects"
        d. turn on some "Editing Options" if need


    這樣就大功告成啦!

    2011年10月17日 星期一

    How to import ssh key from puttygen?


    如果在 Window 的系統上我們會用 puttygen 來生成 ssh key, 但如果我們要拿去 ubuntu 使用該怎麼做?

    首先因為 ubuntu 上使用的 openSSH 的格式和 puttygen 的不同, 所以要先把 private key 轉換成正確的格式, 轉換成功後記得檔案要存成 id_rsa


    接下來把 public key 直接當成純文字存到另一個檔案 id_rsa.pub

    我們把這兩個檔案都上傳到 ubuntu 的機器, 然後放在 ~/.ssh/ 底下, 如果原本就有檔案存在, 就把它覆蓋掉

    最後一件事是要記得改權限, 不然會被視為有問題!

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    Permissions 0644 for '/home/pjack/.ssh/id_rsa' are too open.
    It is recommended that your private key files are NOT accessible by others.
    This private key will be ignored.
    bad permissions: ignore key: /home/pjack/.ssh/id_rsa
    

    chmod 0600 .ssh/id_rsa