描述器
get(self, instance, owner)
- 通路屬性時調用
set(self, instance, value)
- 當對屬性指派時調用
delete(self, instance)
- 删除屬性時調用
- self指代目前執行個體
- instance是owner的執行個體
- owner是屬性的所屬的類
- 描述器實作前提是描述器類執行個體作為類屬性
- 當隻實作get時 (非資料描述符),屬性查找順序是本執行個體優先,get方法次之
- 當實作get和set時(資料描述符) ,屬性查找順序是get方法優先
本質
- 給類添加描述器時可以顯示添加類屬性,或者用setattr注入
注意所謂的類屬性不僅僅類似與x=A()的屬性,類中定義的函數也是類屬性
模拟staticmethod與classmethod
from functools import partial
class StaticMethod:
def __init__(self, fn):
self.fn = fn
def __get__(self, instance, owner):
return self.fn
class ClassMethod:
def __init__(self, fn):
self.fn = fn
def __get__(self, instance, owner):
return partial(self.fn, owner)
class Test:
@StaticMethod
def s_mtd(): # s_mtd = StaticMethod(s_mtd)
print('s_mtd')
@ClassMethod
def c_mtd(cls): # c_mtd = ClassMethod(c_mtd)
print('c_mtd', cls)
if __name__ == '__main__':
Test.s_mtd()
Test.c_mtd()
模拟property
class Property:
def __init__(self, fget=None, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, instance, owner):
return self.fget(instance)
def __set__(self, instance, value):
self.fset(instance, value)
def getter(self):
pass
def setter(self, fset):
self.fset = fset
return self
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
@Property
def name(self): # name=Property(name)
return self._name
@name.setter
def name(self, value): # name=Property(name).setter(name) (value)
self._name = value
@Property
def age(self): # name=Property(name)
return self._age
@age.setter
def age(self, value): # name=Property(name).setter(name) (value)
self._age = value
校驗參數類型
普通裝飾器
import inspect
class TypeCheck:
def __init__(self, key, type):
print('TC init')
self.key = key
self.type = type
def __get__(self, instance, owner):
print('TC get')
if instance is not None:
return instance.__dict__[self.key]
return self
def __set__(self, instance, value):
print('TC set')
if not isinstance(value, self.type):
raise TypeError
instance.__dict__[self.key] = value
def typeassert(cls):
params = inspect.signature(cls).parameters
for name, type in params.items():
if type != type.empty:
setattr(cls, name, type.annotation)
return cls
@typeassert
class Person:
name = TypeCheck('name', str)
age = TypeCheck('age', int)
def __init__(self, name: str, age: int):
self.name = name
self.age = age
tom = Person('tom', 12)
print(tom.name)
類裝飾器
import inspect
class TypeCheck:
def __init__(self, key, type):
print('TC init')
self.key = key
self.type = type
def __get__(self, instance, owner):
print('TC get')
if instance is not None:
return instance.__dict__[self.key]
return self
def __set__(self, instance, value):
print('TC set')
if not isinstance(value, self.type):
raise TypeError
instance.__dict__[self.key] = value
class TypeAssert:
def __init__(self, cls):
self.cls = cls
def __call__(self, name, age):
params = inspect.signature(self.cls).parameters
for key, type in params.items():
if type != type.empty:
setattr(self.cls, key, TypeCheck(key, type.annotation))
return self.cls(name, age)
@TypeAssert
class Person: # Person = TypeAssert(Person)
name = TypeCheck('name', str)
age = TypeCheck('age', int)
def __init__(self, name: str, age: int):
self.name = name
self.age = age
tom = Person('tom', '12')
print(tom.name)
連結清單
class Node:
"""
Description: Node Class
attr item: current Node`s data
attr next: points to the next Node
attr past: points to the last Node
"""
def __init__(self, item: object):
self.__item = item
self.__next = None
self.__past = None
@property
def item(self):
return self.__item
@item.setter
def item(self, value):
self.__item = value
@property
def next(self):
return self.__next
@next.setter
def next(self, value: object):
self.__next = value
@property
def past(self):
return self.__past
@past.setter
def past(self, value: object):
self.__past = value
class LinkedList:
"""
Description: Base class LinkedList
"""
def __init__(self):
self.cur = None
self.head = None
self.length = 0
def append(self, no: object):
raise Exception('Base Method')
def iternodes(self):
raise Exception('Base Method')
def pop(self):
raise Exception('Base Method')
def insert(self, position: int, value: object):
raise Exception('Base Method')
def remove(self, value: object):
raise Exception('Base Method')
class SingleLinkedList(LinkedList):
"""
Description:
attr head: head Node
attr cur: current Node
method append(): append Node
"""
def __init__(self):
super().__init__()
def __iter__(self):
cur_node = self.head
while True:
yield cur_node.item
if not cur_node.next:
break
cur_node = cur_node.next
def __getitem__(self, item):
cur_node = self.head
if isinstance(item, slice):
pass
else:
for _ in range(item):
cur_node = cur_node.next
return cur_node.item
def __setitem__(self, key, value):
cur_node = self.head
for _ in range(key):
cur_node = cur_node.next
cur_node.item = value
def append(self, no: object):
if self.length == 0:
self.cur = Node(no)
self.head = self.cur
else:
self.cur.next = Node(no)
self.cur = self.cur.next
self.length += 1
sl = SingleLinkedList()
sl.append(1)
sl.append(2)
for i in sl:
print(i)
sl[1] = 999
sl[0] = 234
for i in sl:
print(i)
class DoubleLinkedList(LinkedList):
"""
Description:
attr head:
attr cur:
method append:
method pop:
method insert:
method remove:
method iternodes:
"""
def __init__(self):
super().__init__()
def __iter__(self):
cur_node = self.head
while True:
yield cur_node.item
if not cur_node.next:
break
cur_node = cur_node.next
def __reversed__(self):
cur_node = self.cur
while True:
yield cur_node.item
if not cur_node.past:
break
cur_node = cur_node.past
def __getitem__(self, item):
cur_node = self.head
if isinstance(item, slice):
pass
else:
for _ in range(item):
cur_node = cur_node.next
return cur_node.item
def __setitem__(self, key, value):
cur_node = self.head
for _ in range(key):
cur_node = cur_node.next
cur_node.item = value
def append(self, no: object):
if self.length == 0:
self.cur = Node(no)
self.head = self.cur
else:
temp = self.cur
self.cur.next = Node(no)
self.cur = self.cur.next
self.cur.past = temp
self.length += 1
def pop(self):
pop_node = self.cur
pop_node.past.next = None
self.cur = self.cur.past
self.length -= 1
return pop_node
def insert(self, position: int, value: object):
cur_node = self.head
new_node = Node(value)
for _ in range(position - 1):
cur_node = cur_node.next
next_node = cur_node.next
cur_node.next = new_node
new_node.past = cur_node
new_node.next = next_node
next_node.past = new_node
def remove(self, value: object):
cur_node = self.head
while True:
if cur_node.item == value:
cur_node.past.next = cur_node.next
cur_node.next.past = cur_node.past
break
elif not cur_node.next:
raise Exception('NodeNotFound')
cur_node = cur_node.next
def iternodes(self, *, reverse=False):
if not reverse:
cur_node = self.head
while True:
yield cur_node.item
if not cur_node.next:
break
cur_node = cur_node.next
else:
cur_node = self.cur
while True:
yield cur_node.item
if not cur_node.past:
break
cur_node = cur_node.past
異常處理
産生異常
raise 異常執行個體
- Python解釋器自己檢測到異常并引發它
異常捕獲
try:
待捕獲異常的代碼塊
except [異常類型] as e:
異常的處理代碼塊
else:
...
finally:
...
- e為異常的執行個體
- 可寫多個except
- else 沒有任何異常發生則執行
- finally語句塊無論如何都會執行
BaseException
- 所有内建異常類的基類
SystemExit
- sys.exit()引發的異常,異常不捕獲處理,直接交給Python解釋器,解釋器退出
KeyboardInterrupt
- 指令行使用Ctrl+C終端操作
Exception
- 所有内建、非系統退出的異常的基類,自定義異常需要繼承它
SyntaxError文法錯誤
- 此錯誤不可捕獲
ArithmeticError
- 算術計算錯誤,子類有除零異常等
LookupError
- 使用映射的鍵或序列的索引無效時引發的異常的基類:IndexError,KeyError
子產品化
import ... 與import ... as ...
- 找到制定的子產品,加載和初始化它,生成子產品對象
- 在import所在的作用域的局部命名空間中,增加名稱和上一步建立的對象關聯
- 導入頂級子產品,其名稱會加入到本地名詞空間中(dir()),并綁定到其子產品對象
- 導入非頂級子產品,至将其頂級子產品名稱加入到本地名詞空間中,導入的子產品必須用完全限定名通路
- 如果使用as,as後的名稱直接綁定到導入的子產品對象中,并将該名稱加入到本地名詞空間中
from ... import ...與from ... import ... as ...
- from後指定的子產品名隻加載并初始化,不導入
- 對于import子句後的名稱
- 先查from導入的子產品是否具有該名稱屬性,如果不是,則嘗試導入該名稱的子子產品
自定義子產品
- 命名規範
- 全小寫,下劃線來分割
子產品搜尋順序
sys.path
- 傳回清單
- 可被修改,追加新路徑
路徑查找順序
- 程式主目錄
- PYTHONPATH目錄
- 标準庫目錄
sys.modules
- 傳回字典
- 記錄所有加載的子產品
子產品運作
name
- 子產品名,如不指定就是檔案名
- 解釋器初始化時會初始化sys.module字典,建立builtins子產品、main子產品、sys子產品,sys.path
if name == 'main'
- 用于子產品功能測試
- 避免主子產品變更的副作用
子產品的屬性
- file 源檔案路徑
- cached 編譯後的位元組碼檔案路徑
- spec 顯示子產品規範
- name 子產品名
- package 當子產品是包,同name,否則可以設定為頂級子產品的空字元串
包 Package
- 目錄下有一個init.py檔案,導入包時,此檔案内容代表此包
子子產品
- 包目錄下的py檔案、子目錄都是其子子產品
子產品和包總結
-
導入子子產品一定會加載父子產品,導入父子產品一定不會導入子子產品
包是特殊的子產品,包含path屬性
絕對導入,相對導入
絕對導入
- 總是去搜尋子產品搜尋路徑中找
相對導入
- 隻能在包内使用,且隻能用在from中
- . 表示目前目錄
- .. 表示上一級目錄
- ... 表示上上級目錄
通路控制
- from ... import *
- 使用此方法導入子產品時,以_和__開頭的屬性不會導入
- 使用all
- 一個清單,每個元素都是子產品内的變量名
- 定義all後,from ... import * 隻導入all内的屬性
包管理
- setuptools
- 包管理的核心子產品
- pip
- 目前包管理的事實标準
- wheel
- 以二進制安裝,不需要本地編譯
pip install wheel
建立setup.py檔案
# from distutils.core import setup # 可能失敗
from setuptools import setup
setup(name='Distutils',
version='1.0',
description='Python Distribution Utilities',
author='Greg Ward',
author_email='[email protected]',
url='https://www.python.org/sigs/distutils-sig/',
packages=['distutils', 'distutils.command'],
)
- package内容是要管理的包
查詢指令幫助
python setup.py cmd -help
build
- 建立一個build目錄
python setup.py build
- build得到的檔案,直接拷貝到其他項目就可以用
install
python setup.py install
- 如果沒有build,會先build編譯,然後安裝
sdist
python setup.py sdist
- 建立源代碼的分發包
- 在其他地方解壓縮這個檔案,裡面有setup.py,就可以使用python setup.py install安裝,也可以
- pip install XXX.zip直接使用pip安裝這個壓縮包
插件化開發
動态導入
- 運作時,根據使用者需求,找到子產品的資源動态加載起來
- import(name, globals=None, locals=None, fromlist=(), level=0)
- import 本質上就是調用此函數(sys = impot('sys') 等價于import sys),但建議不直接使用,建議使用
- importlib.import_module(name, package=None)
- 支援絕對導入和相對導入,如果是相對導入,package必須設定
插件化程式設計技術
依賴的技術
- 反射:運作時擷取類型的資訊,可以動态維護類型資料
- 動态import:使用importlib
- 多線程:可以開啟一個線程,等待使用者輸入,進而加載指定名稱的子產品
加載時機
- 程式啟動時
- 程式運作中
- 如插件過多,會導緻程式啟動很慢,如果使用者需要時再加載,如果插件太大或依賴多,插件也會啟動慢。
- 是以先加載必須、常用插件,其他插件使用時,發現需要,動态載入
基礎知識補充
slot
- 字典為了查詢效率,必須用空間換時間
- 如果執行個體對象數量過大,那字典占用空間過大
- 如果類定義了slot,執行個體會省略建立dict
- 如果給執行個體增加不在slot的屬性會抛出Attribute異常
- slot可以定義為元組或清單,通常用元組,省空間
- slot不會繼承給子類
未實作和未實作異常
- NotImplemented是個值,單值,是NotImplementedType類的執行個體
- NotImplementedError是類型,是異常,傳回type
運算符重載中的反向方法
- 當正向方法傳回NotImplemented時調用反向方法
git伺服器搭建
gogs
軟體依賴
Mysql
安裝
useradd git
su - git
tar xf gogs*
cd gogs
mysql -uroot -p < scripts/mysql.sql
grant all on gogs.* to 'gogs'@'%' identified by 'gogs';
flush privileges;
配置檔案
mkdir -p custom/conf
cd custom/conf
touch app.ini
啟動gogs
- ./gogs web
- 服務啟動
cp /home/git/gogs/scripts/init/centos/gogs /etc/init.d/
chmod +x /etc/init.d/gogs
chkconfig gogs on
service gogs start