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='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
- 多线程:可以开启一个线程,等待用户输入,从而加载指定名称的模块
加载时机
- 程序启动时
- 程序运行中
- 如插件过多,会导致程序启动很慢,如果用户需要时再加载,如果插件太大或依赖多,插件也会启动慢。
- 因此先加载必须、常用插件,其他插件使用时,发现需要,动态载入
slot
- 字典为了查询效率,必须用空间换时间
- 如果实例对象数量过大,那字典占用空间过大
- 如果类定义了slot,实例会省略建立dict
- 如果给实例增加不在slot的属性会抛出Attribute异常
- slot可以定义为元组或列表,通常用元组,省空间
- slot不会继承给子类
未实现和未实现异常
- NotImplemented是个值,单值,是NotImplementedType类的实例
- NotImplementedError是类型,是异常,返回type
运算符重载中的反向方法
- 当正向方法返回NotImplemented时调用反向方法
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
- 服务启动
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