Python第九周 学习笔记(1)

发布时间:2019-08-29 07:36:04编辑:auto阅读(1389)

    描述器


    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='gward@python.net',
          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

关键字