1. 程式人生 > >Python第九周 學習筆記(1)

Python第九周 學習筆記(1)

學習筆記

描述器

get(self, instance, owner)

  • 訪問屬性時調用

set(self, instance, value)

  • 當對屬性賦值時調用

delete(self, instance)

  • 刪除屬性時調用

    • self指代當前實例
    • instance是owner的實例
    • owner是屬性的所屬的類
  • 描述器實現前提是描述器類實例作為類屬性

  • 當只實現get時 (非數據描述符),屬性查找順序是本實例優先,get方法次之
  • 當實現getset時(數據描述符) ,屬性查找順序是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)
    • name 模塊名
    • import 本質上就是調用此函數(sys = impot(‘sys‘) 等價於import sys),但建議不直接使用,建議使用
    • importlib.import_module(name, package=None)
    • 支持絕對導入和相對導入,如果是相對導入,package必須設置

插件化編程技術

依賴的技術

  • 反射:運行時獲取類型的信息,可以動態維護類型數據
  • 動態import:使用importlib
  • 多線程:可以開啟一個線程,等待用戶輸入,從而加載指定名稱的模塊

加載時機

  1. 程序啟動時
  2. 程序運行中
  • 如插件過多,會導致程序啟動很慢,如果用戶需要時再加載,如果插件太大或依賴多,插件也會啟動慢。
  • 因此先加載必須、常用插件,其他插件使用時,發現需要,動態載入

基礎知識補充


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

  1. ./gogs web

  2. 服務啟動

    gogs下需要建立log目錄

root用戶操作

cp /home/git/gogs/scripts/init/centos/gogs /etc/init.d/
chmod +x /etc/init.d/gogs
chkconfig gogs on
service gogs start

首次登陸
http://IP:Port/install

Python第九周 學習筆記(1)