## 第二章 物件導向三大特性 ### 繼承 繼承允許一個類別(子類別)從另一個類別(父類別)中繼承屬性和方法。透過繼承,子類別可以重用父類別的程式碼,並在此基礎上進行擴展或修改(override)。範例如下 ```python= class Father: def __init__(self, name, age): self.name = name self.age = age def get_name(self): return f"{self.name} call from Father" class Son(Father): def __init__(self, name, age): super().__init__(name, age) son1 = Son("John", 25) print(son1.get_name()) # Output: John call from Father ``` 像上面的程式碼中Son類別並沒有額外覆蓋父類別的函式,則後面在呼叫這函式時會使用到父類別定義的函式。 而下面的程式碼則覆蓋掉父類別的函式,因此輸出變成Son所定義的字串 ```python= class Father: def __init__(self, name, age): self.name = name self.age = age def get_name(self): return f"{self.name} call from Father" class Son(Father): def __init__(self, name, age): super().__init__(name, age) def get_name(self): return f"{self.name} call from Son" son1 = Son("John", 25) print(son1.get_name()) # Output: John call from Son ``` 而繼承的優點除了可以減少重複的程式碼,最重要的是讓程式碼更容易維護,因為在實務上像是遊戲中的角色系統,可能會像warrior及wizard那樣同時繼承entity,這樣在後續的維護上會更加方便,例如每個物體都想要新增一個屬性:耐力值,那麼就只需要在entity類別裡面再加上一個屬性即可。 ![image](https://hackmd.io/_uploads/B1Llcbimee.png) ```python= class Entity: def __init__(self, health, element): self.health = health self.element = element def attack(self, enemy): enemy.health -= 10 print(f"Attacked! Enemy health: {enemy.health}") ``` 在這裡先定義一個base class,當中有每個實體都會有的生命及元素,最後還有一個attack函式。 ```python= class Warrior(Entity): def __init__(self, health, element, strength): super().__init__(health, element) self.strength = strength def attack(self, enemy): damage = self.strength self.strength -= 1 if self.element == "fire" and enemy.element == "ice": damage *= 2 elif self.element == "ice" and enemy.element == "fire": damage /= 2 enemy.health -= damage print(f"Warrior attacks! Enemy health: {enemy.health}") ``` 這裡warrior override了base class的attack函式,如果之後建立Warrior的實例的話,用其呼叫attack函式就會是已經覆蓋過的函式。 ```python= class Wizard(Entity): def __init__(self, health, element, magic_power): super().__init__(health, element) self.magic_power = magic_power ``` 這裡Wizard沒有覆蓋base class的attack函式,所以到時候呼叫會是base class的函式。 ```python= billy = Warrior(100, "fire", 10) # Warrior attacks! Enemy health: 80 bob = Wizard(100, "ice", 10) # Wizard attacks! Enemy health: 90 billy.attack(bob) bob.attack(billy) list_of_entities = [billy, bob] for entity in list_of_entities: print(f"Entity health: {entity.health}, Element: {entity.element}") # Entity health: 90, Element: fire # Entity health: 80, Element: ice ``` 在上面的程式碼當中,我們先定義了一個父類別(Entity),而後我們定義了兩個子類別(Warrior and Wizard)各自都繼承Entity,父類別當中,定義了大家共有的屬性和方法。 兩個子類別則自己新增了屬於自己類別的屬性(strength and magic_power),以及修改(覆蓋掉)父類別有的函式。 由程式碼可看出繼承的其中一個優點:共同的變數或方法可以不用重複寫,像是父類別中的health和element,在子類別繼承以後,就不需要重新定義這兩個變數,但他們會需要呼叫super().__init__()也就是父類別的建構子,而之後子類別一樣可以透過instance.element來存取成員變數。 可以想像成父類別是一個房子的骨架,而子類別是房子後續的搭建,這些後續的搭建都需要在父類別的基礎上繼續搭建,所以必須先建構父類別,因此才會在子類別的建構子中呼叫父類別的建構子。 而super關鍵字 ```python= def __init__(self, health, element, strength): # 子類別的建構子 super().__init__(health, element) # 必須呼叫父類別的建構子 self.strength = strength ``` 上面的attack()函式在父類別當中被定義過,而子類別可以選擇要不要自己重新撰寫一次函式覆蓋掉父類別的函式,或者是也可以不寫,沿用父類別的函式。 ### 多型 ```python= billy = Warrior(100, "fire", 10) # Warrior attacks! Enemy health: 80 bob = Wizard(100, "ice", 10) # Wizard attacks! Enemy health: 90 billy.attack(bob) bob.attack(billy) list_of_entities = [billy, bob] for entity in list_of_entities: print(f"Entity health: {entity.health}, Element: {entity.element}") # Entity health: 90, Element: fire # Entity health: 80, Element: ice ``` 同樣是上面的例子,同樣都是呼叫 attack 這個函式,但是因為billy 和 bob 的類別不同且各自都有覆蓋掉父類別的函式,所以有不同的表現,這就是多型,多型允許不同類別以統一的方式進行調用,但實際執行的行為會因為物件的具體類型有所不同。 ### 封装 在設計類別時,將某些部分隱藏起來,使外界要使用這個類別時,只能使用類別定義的公開函式及變數。 #### 這樣有什麼優點 隱藏實作細節:像是python官方的資料型態 list 內部實作的細節使用者無法知道,但使用者可以知道的是呼叫clear()可以清空現在list內的資料。這種隱藏實作細節(抽象),讓使用者不需要知道細節的方式在現今程式設計當中很常見。 ```python= def shuffle(self, x): """Shuffle list x in place, and return None.""" randbelow = self._randbelow for i in reversed(range(1, len(x))): # pick an element in x[:i+1] with which to exchange x[i] j = randbelow(i + 1) x[i], x[j] = x[j], x[i] ``` 上面的程式碼是官方原始碼的random.py中的shuffle,可以讓一個list中的元素進行打亂,在這個例子當中shuffle函式使用到了_randbelow(實際上這個變數是一個函式變數,來自於_randbelow_with_getrandbits),避免外界能夠直接呼叫到這些私有函式。 ## 進階 ### 繼承的額外補充 1. 由於python是動態語言,所以繼承這方面有些地方會與靜態語言如:`c++`有所不同,例如`c++`的虛擬函式在python裡面根本不需要,除了python都是run time才會知道型態以外,python的list裡面可以放不同的類型,種種原因使得python使用起來非常的靈活,但也是因為這樣比`c++`慢很多。 2. 繼承建立的是一種非常強的 「is-a」 關係。雖然它在某些場景下很有用,但濫用會導致程式碼變得脆弱、僵化且難以維護。這也是為什麼現代軟體設計原則大力提倡 「多用組合,少用繼承 (Favor Composition over Inheritance)」。 一樣是上面的Wizard Warrior例子 ```python= class Warrior(Entity): def __init__(self, health, element, strength): super().__init__(health, element) self.strength = strength def attack(self, enemy): damage = self.strength self.strength -= 1 if self.element == "fire" and enemy.element == "ice": damage *= 2 elif self.element == "ice" and enemy.element == "fire": damage /= 2 enemy.health -= damage print(f"Warrior attacks! Enemy health: {enemy.health}") billy = Warrior(100, "fire", 10) ``` 假設billy想要切換攻擊策略呢,假如他想要轉行到Wizzard的話呢,舊有寫法會導致這種想法不好實現。 換成組合(Composition)的寫法呢? 我們不再讓 Warrior 是 一個會特殊攻擊的 Entity,而是讓一個通用的 Entity 擁有 一個「戰士攻擊策略」。 ```python class AttackStrategy: """一個抽象的基底類別,定義了策略的介面。""" def attack(self, attacker, enemy): # 'attacker' 是指發動攻擊的實體本身 raise NotImplementedError class DefaultAttack(AttackStrategy): """原本 Entity 的預設攻擊行為""" def attack(self, attacker, enemy): damage = 10 enemy.health -= damage print(f"A default attack hits! Enemy health: {enemy.health}") class WarriorAttack(AttackStrategy): def __init__(self, strength): self.strength = strength def attack(self, attacker, enemy): # 注意:現在是從 attacker 身上取得 element damage = self.strength # 攻擊行為會消耗自己的力量 self.strength -= 1 if attacker.element == "fire" and enemy.element == "ice": damage *= 2 elif attacker.element == "ice" and enemy.element == "fire": damage /= 2 enemy.health -= damage print(f"Warrior strategy used! Enemy health: {round(enemy.health)}") class WizardAttack(AttackStrategy): def __init__(self, magic_power): self.magic_power = magic_power def attack(self, attacker, enemy): # 為了讓例子完整,我們也給 Wizard 加上攻擊邏輯 damage = self.magic_power enemy.health -= damage print(f"Wizard strategy used! Enemy health: {enemy.health}") ``` 每個策略類別都只關心一件事:如何執行攻擊。 attack 方法現在需要傳入 attacker 和 enemy,因為策略本身不儲存 health 或 element,它需要從發動攻擊的實體身上獲取這些資訊。 ```python= class Entity: def __init__(self, health, element, strategy: AttackStrategy): self.health = health self.element = element # 組合的核心:Entity "has an" attack_strategy self.attack_strategy = strategy def attack(self, enemy): # 委派!Entity 自己不決定如何攻擊,而是交給它的策略物件 self.attack_strategy.attack(self, enemy) ``` 由上面的例子可以知道,我們從is-a的關係轉換成has-a的關係,這樣做以後,就算之後想要修改攻擊策略,想要換一個職業的話都可以很輕鬆地做到。 3. 因為是強力的is-a關係,所以擁有緊耦合的關係出現 這是繼承最核心的問題。子類別與父類別之間存在著極強的耦合關係,因為子類別不僅繼承了父類別的公開介面 (public interface),更繼承了其內部實作細節 (implementation details)。 父類別的改動會輕易破壞子類別:如果父類別的作者修改了某個方法的內部實作,即使方法的簽名(名稱和參數)完全沒變,也可能導致所有依賴這個實作的子類別出現非預期的錯誤。 子類別被父類別綁架:一旦建立了繼承關係,子類別就很難再從這個繼承體系中脫離。 經由上面的兩個繼承缺點可以知道,組合的實用性是遠遠大於繼承的 * 繼承定義了物件是什麼 (identity)。它是一種靜態的、分類學上的關係。這種思維模式是:「我是一個戰士,所以我能用戰士的方式攻擊。」 * 組合定義了物件能做什麼 (behavior)。它是一種動態的、功能性的關係。這種思維模式是:「我是一個實體,我恰好擁有一個戰士的攻擊模組,所以我能用戰士的方式攻擊。如果需要,我可以隨時換上一個巫師的攻擊模組。」 然而,這並不代表繼承一無是處。我們批判的主要是「實作繼承」,即為了重用程式碼而繼承一個具體的父類別。 相對地,「介面繼承」是一種非常強大且正確的用法。當一個類別繼承自一個抽象基底類別(如 Pygame 的 Sprite 或我們自訂的 AttackStrategy),它的目的不是偷懶,而是為了「簽署一份合約」,承諾自己會遵守某個規範。這種繼承是實現多型和融入框架的關鍵,它往往是組合模式的完美盟友,而非敵人。 ### 鴨子型別 也就是說不管類型的型別為何,只要實作到這個同名的成員函式,就可以呼叫這個函式。 ```python= class Matrix: def __init__(self, rows, cols): self.rows = rows self.cols = cols self.data = [[0] * cols for _ in range(rows)] def print(self): for row in self.data: print(" ".join(map(str, row))) class Player: def __init__(self, name): self.name = name self.score = 0 def print(self): print(f"Player: {self.name}, Score: {self.score}") def print_object(obj): if hasattr(obj, 'print'): obj.print() else: print("錯誤: 不是鴨子型別") obj_list = [Matrix(3, 3), Player("Alice"), "這不是鴨子型別"] for obj in obj_list: print_object(obj) # 輸出: # 0 0 0 # 0 0 0 # 0 0 0 # Player: Alice, Score: 0 # 錯誤: 不是鴨子型別 ``` 這段程式碼沒有使用到繼承,但卻可以實現多型的效果。 傳統的多型依賴於繼承體系,確保所有子類別都共享一個共同的介面。而鴨子型別則更加靈活,它不要求物件之間有繼承關係,只要求它們在被使用時具有相同的「行為」(例如,有名稱相同的方法)。 正如俗話所說:「如果它走路像鴨子,叫聲像鴨子,那麼它就是一隻鴨子。」 而在上面鴨子型別的例子當中,Matrix與Player一點關係都沒有,在實務中如果同時需要很多多型的需求,使用繼承的方式會導致程式碼冗長。 例:可以print的定義一個printable類別,可以被攻擊的定義一個attackable類別,然後想要讓一個類別可以被print就繼承printable,同樣的操作重複很多,這樣一個類別就會繼承好幾個不同類別,這樣的程式碼會非常的長,改為使用鴨子型別的話,每個類別不用特別繼承多種類別,整體的程式碼也會更簡潔。 ```python= class JPG: def export_to_bytes(self): return b'\xff\xd8\xff\xdb\x00\x84\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\x08\x09' class PNG: def export_to_bytes(self): return b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00' list_of_images = [JPG(), PNG(), JPG(), PNG(), PNG()] def export_images_to_bytes(images): bytes_list = [] for image in images: bytes_list.append(image.export_to_bytes()) return bytes_list ``` 這是另一個例子,只要PNG跟JPG都有同樣名字的函式,那麼外面就只要呼叫這個函式即可,就算再實作一個新的檔案類型(例如:zip、adpasdkopa),也只要確保他也有一個函式叫做export_to_bytes,那麼我原本寫的程式碼就完全不用再動,這就是開閉原則,對擴展開放,對修改封閉。 ### 反射 指的是程式有能力檢視、存取、甚至修改自己的狀態或行為。 聽起來很繞口。直接用例子解釋比較好。 ```python= class People: def __init__(self, name, age): self.name = name self.age = age self.friends = [] self.enemies = [] self.known_people = set() self.lucky_number = 87 self.favourite_color = "blue" def __str__(self): result = "" for attr in dir(self): if not attr.startswith("__"): result += f"{attr}: {getattr(self, attr)}\n" return result amy = People("Amy", 30) print(amy) #output age: 30 enemies: [] favourite_color: blue friends: [] known_people: set() lucky_number: 87 name: Amy ``` 上面這個例子是反射的其中一個應用,由於我們在People類別中定義了很多成員變數,當我們其他函式想要存取到所有變數,例如這裡的str(也就是將其轉換成字串使print可以更好的將其打印出來),就可以使用到反射來動態存取到所有成員變數,這樣即使後面有新的成員變數的話,就不用再動到str這個函式的東西(符合開閉原則)。 另一個例子: ```python= class Server: def __init__(self, name, ip): self.name = name self.ip = ip def get(self): return f"Server Name: {self.name}, IP Address: {self.ip}" def change_ip(self, new_ip): self.ip = new_ip return f"IP Address changed to: {self.ip}" def dispatch(server, command, *args): if not hasattr(server, command): raise AttributeError(f"Server does not have method '{command}'") method = getattr(server, command) if not callable(method): raise TypeError(f"'{command}' is not a callable method") return method(*args) server = Server("MyServer", "192.168.1.1") # starting the server user_command = input("Enter command to execute on server: ").strip() try: result = dispatch(server, user_command) print(result) except AttributeError as e: print(f"Error: {e}") ``` 如果不用反射寫的話會長這樣 ```python= # 不使用反射的寫法 if user_command == "get": print(server.get()) elif user_command == "change_ip": new_ip = input("Enter new IP address: ").strip() print(server.change_ip(new_ip)) ``` 使用反射的話,想要為這個類別新增一個功能就只要直接新增成員函式就好,其他部分都不用修改,相反地如果不使用反射的話,就要一直新增elif,當程式很龐大的時候,就會非常的醜陋(屎山代碼)。 透過上面兩個例子,可以發現反射就是可以在程式可以檢視程式自己本身的行為,雖然聽起來還是很繞口,如上面的例子:People在寫好成員變數以後,後面的程式還是可以透過dir()函式去取得People這個類別的成員變數,在這裡成員變數是程式的一部份,dir()也是程式的一部份,所以就符合定義(程式可以檢視程式自己本身的行為)。 #### 反射的應用: 序列化及反序列化:像是接下來介紹的pygame,如果想要將遊戲存檔下來,就將現在遊戲的狀態寫入檔案中,而程式就是一大堆class組成的,所以可以透過反射取得程式本身的狀態,將其轉換成字串然後寫入檔案,讀取時再將其轉換成可以用的類別。也就是序列化和反序列化。 ## License ```markdown= A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations, which became Zope Corporation. In 2001, the Python Software Foundation (PSF, see https://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation was a sponsoring member of the PSF. All Python releases are Open Source (see https://opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2 and above 2.1.1 2001-now PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== Python software and documentation are licensed under the Python Software Foundation License Version 2. Starting with Python 3.8.6, examples, recipes, and other code in the documentation are dual licensed under the PSF License Version 2 and the Zero-Clause BSD license. Some software incorporated into Python is under different licenses. The licenses are listed with code falling under that license. PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ---------------------------------------------------------------------- Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ```