Python第十一周学习总结

异常处理、模块化、包管理、插件化开发、其他知识等

目录

一、异常处理 1

1、异常 Exception 1

2、 产生异常 1

3、 异常捕获 2

4、 异常类即继承层次 5

5、 BaseException及子类 9

6、 Exception及子类 10

7、 异常的捕获 10

8、 as子句 10

9、 finally 子句 11

10、 finally执行时机 11

11、 异常传递 11

12、try 的嵌套 13

13、异常的捕获时机 14

14、else子句 14

15、总结 15

二、模块化 16

1、模块化 16

2、 导入语句 16

3、 自定义模块 19

4、模块搜索顺序 19

5、模块的重复导入 20

6、模块运行 20

7、If __name__ == ‘__ main__ ‘:用途 20

8、 模块的属性 21

9、包 22

10、子模块 22

11、 模块和包的总结 23

12、绝对导入和相对导入 23

13、访问控制 23

14、 from … import * 和__all__ 24

15、 包和子模块 24

16、总结 24

17、模块变量的修改 25

三、 包管理 26

1、为什么使用包管理 26

2、主要工具 26

3、使用setup.py打包 26

4、build命令、编译 27

5、install命令,安装 28

6、sdist命令,分发 28

7、wheel包 28

四、 插件化开发 29

1、 __import__()内建函数 29

2、importlib.import_module() 30

3、插件化编程技术 31

4、加载的时机 31

5、应用 31

五、基础知识补充的 32

1、__slots__ 32

2、未实现和未实现异常 33

3、运算符重载中的反向方法 35

六、Git服务搭建 36

 

一、异常处理

1、异常 Exception

错误Error

逻辑错误:算法写错了,加法写成了减法。

笔误:变量名写错了,语法错误。

错误可以避免的

 

异常Exception

本身就是意外情况。一些意外,导致程序无法正常的执行下去。

是不可避免的。

 

错误和异常

在高级编程语言中,一般都有错误和异常的概念,异常是可以捕获的并被处理的,但是错误是不能捕获的。

with open(‘test’) as f:
pass

 

错误信息:

Traceback (most recent call last):

File “C:/Users/WCL/PycharmProjects/untitled1/package/test1/异常处理.py”, line 1, in <module>

with open(‘test’) as f:

FileNotFoundError: [Errno 2] No such file or directory: ‘test’

 

def 0A():
pass

 

File “C:/Users/WCL/PycharmProjects/untitled1/package/test1/参数检查.py”, line 142

class typeassert

^

SyntaxError: invalid syntax

 

一个健壮的程序,尽可能的避免错误。

尽可能的捕获,处理各种异常。

 

2、产生异常

产生:raise语句显示的抛出异常。

Python解释器自己检测到异常并引发他。

def foo():
print(‘—–‘)
def bar():
print(1/0)
bar()
print(‘after’)
foo()

def bar():
print(‘+++++++++++++’)
raise Exception(‘Exc’)
print(‘+-+-+-+-+-+’)
bar()

 

程序会在异常抛出的地方中断执行,如果不进行捕获,就会提前结束程序。

 

raise语句

raise后什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛出类型异常。很少利用的方式。

raise

后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化。

异常必须出自BaseException

sys.exc_info()查看异常所在的元素。

sys.exc_info() ,后面是个元组。(异常类、异常对象,trackback)

 

 

3、异常捕获

try:

待捕获异常的代码块

except[异常类型]:

异常的处理代码块

 

try:
print(‘++++++++++++++++’)
c = 1/0
print(‘—————-‘)
except:
print(‘catch the exception’)
print(‘outer’)

 

++++++++++++++++

catch the exception

Outer

执行到c = 1/0时候产生异常并抛出,由于使用了语句捕捉这个异常,所以产生异常位置后面的语句将不再执行了,转而执行对象except以外的语句。

1)捕获指定类型的异常。

try:
print(‘++++++++++++++++’)
c = 1/0
print(‘—————-‘)
except ArithmeticError:
print(‘catch the ArithmeticError:’)
print(‘outer’)

 

 

++++++++++++++++

catch the ArithmeticError:

Outer

 

 

 

 

 

特别关心的异常放在最上面。

自己定义的异常。

Exception 非退出性异常。

捕获原则:

4、异常类即继承层次

def exc_hierarchy(exc=BaseException, level=-1):
name = exc.__name__
if level == -1:
print(name)
else:
print(“{} +– {}”.format(‘    ‘ * level, name))
for sub in exc.__subclasses__():
exc_hierarchy(sub, level+1)

 

BaseException

+– Exception

+– StopAsyncIteration

+– OSError

+– BlockingIOError

+– FileNotFoundError

+– IsADirectoryError

+– TimeoutError

+– InterruptedError

+– ProcessLookupError

+– NotADirectoryError

+– ConnectionError

+– BrokenPipeError

+– ConnectionAbortedError

+– ConnectionRefusedError

+– ConnectionResetError

+– UnsupportedOperation

+– FileExistsError

+– ChildProcessError

+– PermissionError

+– ArithmeticError

+– FloatingPointError

+– OverflowError

+– ZeroDivisionError

+– AttributeError

+– SyntaxError

+– IndentationError

+– TabError

+– SystemError

+– CodecRegistryError

+– ImportError

+– ZipImportError

+– BufferError

+– LookupError

+– IndexError

+– KeyError

+– CodecRegistryError

+– NameError

+– UnboundLocalError

+– TypeError

+– error

+– StopIteration

+– AssertionError

+– Warning

+– UserWarning

+– DeprecationWarning

+– UnicodeWarning

+– PendingDeprecationWarning

+– ImportWarning

+– RuntimeWarning

+– ResourceWarning

+– SyntaxWarning

+– BytesWarning

+– FutureWarning

+– Error

+– ValueError

+– UnicodeError

+– UnicodeEncodeError

+– UnicodeDecodeError

+– UnicodeTranslateError

+– UnsupportedOperation

+– ReferenceError

+– RuntimeError

+– RecursionError

+– NotImplementedError

+– _DeadlockError

+– MemoryError

+– EOFError

+– GeneratorExit

+– KeyboardInterrupt

+– SystemExit

 

 

 

 

5、BaseException及子类

1)BaseException所有内建异常类的基类是BaseException。

 

2)SystemExit

sys.exit()函数引发的异常,异常不捕获处理,就直接交给Python解释器,解释器退出。

 

import sys
print(‘++++’)
sys.exit(1)
print(‘sysexit’)
print(‘—–‘)

 

++++

 

Process finished with exit code 1

未进行捕获的情况下,

解释器直接退出了。

 

 

import sys
try:
print(‘++++’)
sys.exit(1)
except SystemExit:
print(‘sysexit’)
print(‘—–‘)

 

++++

sysexit

—–

捕获的情况下正常执行,且被捕获。

3)Keyboardinterrupt

对应捕获用户中断的行为 Ctrl + c

 

6、Exception及子类

Exception是所有内建的,非系统退出的异常的基类,自定义异常应该定义继承自它。

 

  • SyntaxError语法错误,Python中也归到Exception类中,但是语法错误是不可被捕获的。
  • ArithmeticError所有算数计算引发的异常,其子类有除零异常等。
  • LookupError 使用映射的键或者序列的索引无效是引发的异常的基类:indexerror keyerror
  • 自定义的异常:从Exception继承的类。

 

7、异常的捕获

Except可以捕获多个异常。

捕获的原则:捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块。

如果被一个except语句块捕获,其他的except就不会再次捕获了。

如果没有任何一个except语句捕获到这个异常,则该异常向外抛出。

捕获的原则,从小到大,从具体到广泛。

8、as子句

被抛出的异常,应该是异常的实例,获得这个对象的话,使用as子句。

class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print(11111111)
print(‘{}{}’.format(e.code,e.message))
except Exception as e:
print(‘{}’.format(e))

 

__init__() missing 2 required positional arguments: ‘code’ and ‘message’

raise后面有特定的参数,如果没有的话就是无参形式。

 

9、finally 子句

Finally 最终,即最后都会是要一定执行的。try…..finally不管有没有异常都会执行。

Finally中一般都是放置资源的清理,释放工作的语句。

也可以在finally中再次捕获异常。

10、finally执行时机

def foo():
try:
return 3
finally:
print(‘finally’)
print(‘—‘)
print(foo())

 

尽管函数有return返回语句,但是finally语句还是要执行的,最后才返回return语句。

拿的值是最后一个return。

11、异常传递

def foo1():
return 1/0

def foo2():
print(‘foo2 —-‘)
foo1()
print(‘foo2++++’)
foo2()

foo2调用了foo1,foo1产生的异常传递到了foo2中

异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出,如果内层捕获并处理了异常,外部就不能捕获的到了。

如果到了最外层还是没有被处理,就会中断异常所在的线程的执行。

import threading
import time

def foo1():
return 1/0

def foo2():
time.sleep(3)
print(‘foo2—-‘)
foo1()
print(‘foo2++++’)
t = threading.Thread(target=foo2)
t.start()

while True:
time.sleep(1)
print(‘Everything OK’)
if t.is_alive():
print(‘live’)
else:
print(‘dead’)

 

未进行捕获异常,异常抛出直接中断了线程。

sys.exc_info() ,后面是个元组。(异常类、异常对象,trackback)

 

 

 

 

12、try 的嵌套

try:
try:
ret = 1/0
except KeyError as k:
print(k)
else:
print(‘ok’)
finally:
print(‘finally’)
except:
print(‘c ok’)
finally:
print(‘fin’)

 

内部捕获不到异常,会向外层传递异常。

但是如果内层有且有finally而且其中有return、break语句,否则就不会继续往外抛出异常。

 

def foo():
try:
ret = 1/0
except KeyError as F:
print(k)
finally:
print(‘finally a ‘)
return   #异常直接被丢弃
try:
foo()
except:
print(‘+++++’)
finally:
print(‘——-‘)

 

有return语句,异常直接被丢弃。

 

13、异常的捕获时机

  • 立即捕获

需要立即返回一个明确的结果

def parse_int(s):
try:
return int(s)
except:
return 0
print(parse_int(‘s’))

 

被return直接返回0

  • 边界捕获

封装产生了边界。

  • 一个模块,用户调用了这个模块的时候捕获异常,异常内部不需要捕获,处理异常,一旦内部处理了,外部调用者无法感知异常了
  • Open函数,出现的异常交给调用者处理,文件存在,就不用创建了,看是否修改修改还是删除。
  • 自己写了一个类,使用open函数,但是文件出现异常不知道如何处理,就继续向外层抛出,一般来说最外层也是边界,必须处理异常,如果不处理的话,线程就会推出。

14、else子句

else子句,没有异常发生,则执行。

try:
ret = 1/0
except ArithmeticError as e:
print(e)
else:
print(‘ok’)
finally:
print(‘fin’)
####division by zero
###fin

 

15、总结

try:

<语句> #运行别的代码

except<异常类>:

<语句>  #捕获某种类型的异常

except<异常类> as <变量名>:

<语句>   #捕获某种类型的异常并获得对象

else:

<语句> #如果没有异常发生

finally:

<语句>  #推出try的时候总会执行

try的工作原理

  • 如果try中语句执行时候会发生异常,搜索except子句,并执行第一个匹配该异常的except子句。
  • 如果try中语句执行时发生异常,却没有匹配except子句,异常将被递交到外层的try,如果外层不处理这个异常,异常将继续向外层传递,如果都不处理该异常,则会传递到最外层,如果还没有处理,就会终止异常所在的线程。
  • 如果try执行时候没有异常,将执行else子句中的语句。
  • 无论try中是否发生异常,finally子句最终都会执行。

 

 

二、模块化

1、模块化

一般来说,编程语言中,库、包、模块是一种概念,是代码组织方式。

 

Python中只有一种模块对象, 但是为了模块化组织模块的便利,提供了一个概念–包模块module,指的是Python的源代码文件。

 

包package,指的是模块组织在一起和包名同名的目录及其相关文件。

 

2、导入语句

语句 含义
Import模块1[模块2] 完全导入
Import…as….. 模块别名

 

Import 的作用:将需要的模块的名称引用到当前所有的模块的名词空间中。

加载到了sys.modules里面去了。

from (后面是模块)import(类、函数)

from pathlib import *

from子句中指定的模块,加载并初始化,(并不是导入)。

 

Import语句:

  • 找到指定的模块,加载并初始化他,生成模块对象。找不到,抛出importError异常。
  • Import所在的作用域的局部命名空间内,增加名称和上一步创建的对象关联。

import functools
print(dir())
print(functools)
print(functools.wraps)

 

1,[‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘functools’]

2,<module ‘functools’ from ‘C:\\Users\\WCL\\AppData\\Local\\Programs\\Python\\Python35\\lib\\functools.py’>

3,<function wraps at 0x00000018C691F620>

import os.path
print(1,dir())
print(2,os)
print(3,os.path)

 

1 [‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘os’]

2 <module ‘os’ from ‘C:\\Users\\WCL\\AppData\\Local\\Programs\\Python\\Python35\\lib\\os.py’>

3 <module ‘ntpath’ from ‘C:\\Users\\WCL\\AppData\\Local\\Programs\\Python\\Python35\\lib\\ntpath.py’>

 

import os.path as osp
print(dir())
print(osp)

 

1 [‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘osp’]

2 <module ‘ntpath’ from ‘C:\\Users\\WCL\\AppData\\Local\\Programs\\Python\\Python35\\lib\\ntpath.py’>

 

总结:

导入顶级模块,其名称会加入到本地名词空间中,并绑定到其模块对象。

导入非顶级模块,只是将其顶级模块名称加入到本地名词空间中。导入的模块必须使用完全限定的名称来访问。

如果使用了as,as后面的名称直接绑定到导入的模块对象,并将该名称加入到本地名词空间中。

语句 含义
from…import.. 部分导入
From…import…as…. 别名

 

From语句:

from pathlib import Path,PosixPath   #在当前名词空间指定导入该模块的指定成员
print(dir())

 

[‘Path’, ‘PosixPath’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’]

 

from pathlib import * #在当前名词空间导入该模块所有公共成员(非下划线开头)
print(dir())

[‘Path’, ‘PosixPath’, ‘PurePath’, ‘PurePosixPath’, ‘PureWindowsPath’, ‘WindowsPath’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’]

 

from functools import wraps as wr,partial
print(dir())

 

[‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘partial’, ‘wr’]

 

from os.path import exists #加载、初始化os、os.path模块,exists加入到本地名词空间并绑定

if exists(‘c:/t’):
print(‘yes’)
else:
print(‘no’)
print(dir())
print(exists)

 

no

[‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘exists’]

<function exists at 0x000000212F72B268>

import os

print(os.path.exists)
print(exists)
print(os.path.__dict__[‘exists’])
print(getattr(os.path,’exists’))

 

通过上面四种方式获得同一个对象。

 

总结:

找到from子句中指定的模块,加载并初始化他(不是导入)。

对于import子句后面的名称。

先查from子句导入的模块是否具有该名称的属性。

如果不是,则尝试导入该名称的子模块。

还没找到,则抛出importError异常

这个名称保存到本地名词空间中,如果有as子句,则使用as子句后面的名称。

from pathlib import Path
print(1,Path,id(Path))

import pathlib as p1
print(2,dir())
print(3,p1)
print(4,p1.Path,id(p1.Path))

 

1 <class ‘pathlib.Path’> 784869820392

2 [‘Path’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘p1’]

3 <module ‘pathlib’ from ‘C:\\Users\\WCL\\AppData\\Local\\Programs\\Python\\Python35\\lib\\pathlib.py’>

4 <class ‘pathlib.Path’> 784869820392

看出导入的Path和p1.Path是同一个对象。

 

3、自定义模块

自定义模块:.py文件就是一个模块。

 

自定义模块名命名规范:

  • 模块名就是文件名
  • 模块名必须符合标识符的要求,是非数字开头的字母数字和下划线的组合。
  • 不能使用系统模块名来避免冲突,除非知道模块名的用途。
  • 模块名全为小写,下划线来分隔。

 

 

4、模块搜索顺序

import sys

for i in sys.path:
print(i)

 

C:\Users\WCL\PycharmProjects\untitled1\package\exercise

C:\Users\WCL\PycharmProjects\untitled1

C:\Users\WCL\PycharmProjects\untitled1\venv\Scripts\python35.zip

C:\Users\WCL\AppData\Local\Programs\Python\Python35\DLLs

C:\Users\WCL\AppData\Local\Programs\Python\Python35\lib

C:\Users\WCL\AppData\Local\Programs\Python\Python35

C:\Users\WCL\PycharmProjects\untitled1\venv

C:\Users\WCL\PycharmProjects\untitled1\venv\lib\site-packages

C:\Users\WCL\PycharmProjects\untitled1\venv\lib\site-packages\setuptools-28.8.0-py3.5.egg

C:\Users\WCL\PycharmProjects\untitled1\venv\lib\site-packages\pip-9.0.1-py3.5.egg

使用sys.pah查看搜索顺序。

 

当加载一个模块的时候,需要从这些搜索路径中从前到后依次查找,并不搜索这些目录的子目录,搜索到模块就加载,搜索不到就抛出异常。

 

路径可以为zip文件 egg文件、字典。

.egg文件,由setuptools库创建的包,第三方库常见的格式,添加了元数据,版本号等,依赖项。

信息的zip文件。

 

路径顺序为:程序的主目录,程序运行的主程序脚本所在的目录,Pythonpath目录,环境变量PYTHONPATH设置额目录也是搜索模块的路径。

标准库目录,Python自带的库模块所在目录。

 

Sys.path可以被修改,追加新的目录。

5、模块的重复导入

 

模块并不会重复导入,就是查字典的过程(从前向后找。)所有加载的模块都会记录在sys.modules中,sys.modules是存储已经加载过的所有模块的字典。

 

6、模块运行

__name__ 每个模块都会定义一个__name__特殊变量来存储当前模块的名称,如果不指定,则默认为源代码文件名,如果是包则有限定名。__name__这个属性,用来定义当前的文件名称。

 

解释器初始化的时候,会初始化sys.modules字典,(保存已加载的模块),创建buildtins(全局函数、常量),模块,__main__、sys模块,以及模块搜索路径sys.path.

搜索路径也要加到sys.path中来。

python是脚本语言,任何一个脚本都可以直接执行,也可以作为模块被导入。

 

当标准输入、脚本或交互式读取的时候,会将模块的 __name__,设置为__main__,模块的顶层代码就在__main__这个作用域中执行,顶层代码:模块中缩进外层的代码。

如果是import导入的,其__name__默认就是模块名。

从哪里运行就把__name__ 改为__main__

 

7、If __name__ == __ main__ :用途

1)本模块的功能测试。

对于非主模块,测试本模块内的函数,类。

2)避免主模块变更的副作用。

顶层代码,没有封装,主模块使用时候没有问题,但是一旦有了新的主模块,老的主模块成了被导入模块,由于原来的代码没有封装,一并执行

 

Sys.path(搜索路径)

Sys.moduels (字典,已加载的在里面。)

 

if __name__ == ‘__main__’:
print(‘in __main__’)
else:
print(‘in import module’)

 

in __main__

 

import m2

 

in import module

 

8、模块的属性

属性 含义
__file__ 字符串,源文件路径
__cached__ 字符串,编译后的字节码文件路径
__spec__ 显示模块的规范
__name__ 模块名
__package__ 当模块是包,同__name__:否则,可以设置为顶级模块的空字符串

 

 

 

9、包

包:特殊的模块。

Python支持目录。

 

项目中新建一个目录m

Import m

print(m)

Print(type(m))

Print(dir())#  没有__file__属性

可以导入目录m,m也是文件,可以导入,目录模块写入代码,在其目录下简历一个特殊的文件__init__.py,在其中写入代码。

 

Pycharm 中创建普通的文件夹和Python的包不同,普通包只是创建目录,后面的则是创建一个带有_init__.py文件的目录即包。

 

10、子模块

包目录下的py文件,子目录都是其子模块。

 

如上建立子模块目录和文件,所有的py文件中就写一句话print(__name__)

 

Import * 只是拿共有的模块的内容。公共成员,私有的不能拿。

Import m (加载m)

Import m.m1(加载m和m1)

Import m.m2.m21(加载m,m2,m21)

From m import m1 从m中加载m1

From m.m2 import m21 三层加载。

 

保留__init__文件。

 

11、模块和包的总结

包能够更好的组织模块,由其是在大的规模下代码行数很多,可以将其拆分为很多子模块,便于使用某些功能就在家相应的子模块。

 

包目录中 __init__.py 是包在导入的时候就会执行,内容可以为空,也可以用于该报初始化工作的代码。

 

导入子模块一定会导入父模块,导入父模块就不会加载子模块。

包目录之间只能使用.点号作为间隔符,表示模块及其子模块之间的层级关系。

 

模块也是封装,如同类,函数,不过其能够封装变量、类、函数。

模块就会命名空间,其内部的顶层标识符,都是其属性,可以通过__dict__或者dir()查看。

 

包也是模块,但是模块不一定是包,包是特殊的模块,是一种组织方式,包含__path__属性。

 

From ison import encoder:   不可以执行ison.dump

Import json.encoder:  可以执行json.dump

 

12、绝对导入和相对导入

绝对导入:

在import 语句或者from导入模块,模块名称前不是以.开头的,绝对导入总是去搜索模块搜索路径中找。

相对导入:

包内使用相对的路径。且只能用在from语句中,不在包外用。在顶层用绝对导入。

使用 …上一级的上一级 ..上一级 .同一级。不在顶层使用相对导入。

对于包来说正确的使用方式还是在顶级模块中使用这些包。

 

13、访问控制

下划线或者双下划线开头的模块能够被导入,都可以成功的导入,因为他们都是合法的标识符,都可以用作模块名。

 

模块内的标识符:

普通变量,保护变量,私有变量,特殊变量,都没有被隐藏,也就是说模块内没有私有的变量,在模块定义中不做特殊处理。

使用from可以访问所有变量。

 

14、from … import * 和__all__

使用from … import *导入。起到作用的是from m import *。所有共有成员非子成员的全部导入。会影响当前的名词空间。

定义了__all__  使用all指定导入的是哪些。

 

使用__all__是一个列表,元素是字符串,每个元素都是一个模块的名称。(变量名)

 

 

 

 

15、包和子模块

如何访问到一个模块中的一个变量呢:

  • 直接导入整个模块  import
  • 直接导入from 模块中import 需要的属性。
  • 利用from 模块import* 利用__all__指定需要导入的名称。
  • 在py中增加from . import 模块。

 

16、总结

  • 使用from xyz import *导入
  • 如果模块没有__all__,from xyz import * 只是导入非下划线开头的模块的变量,如果是包,子模块不会导入,除非在__all__中设置,或者使用py文件中使用相对导入。
  • 如果模块有__all__,from xyz import * 只导入__all__列表中指定的名称,哪怕是这个名词是下划线开头或者子模块。
  • From xyz import * 方式带入,使用简单,但是其副作用是导入大量不需要的变量,甚至造成名字的冲突,而__all__可控制被导入模块在这种导入方式下能够提供的变量名称,就是为了阻止from xyz import *导入过多的模块变量,从而避免冲突,因此,编写模块时候,尽量加入__all__

 

  • From module import name1,name2导入

导入时明确的,导入子模块,或者导入下划线开头的名称,可以有控制的导入名和其对应的对象。

17、模块变量的修改

模块对象是同一个,因此模块的变量也是同一个,对模块变量的修改,会影响所有者,除非万不得已,不要修改模块的变量。

猴子补丁,也可以通过打补丁的方式,修改模块的变量,类和函数等内容。

 

 

三、包管理

1、为什么使用包管理

目的是为了便于共享。为了更多项目调用使用,或者共享给别人,就需要打包,目的是为了复用。

Pypi(Python Package Index)公共的模块存储中心。https://pypi.python.org/pypi

2、主要工具

(1)distutils  官方标准库,使用安装脚本setup.py来构建、安装包。

(2)setuptools 是替代distutils的增强版工具集,包含easy_install工具,使用ez_setup.py文件,支持egg格式的构建和安装。

提供查询,下载,安装,构建,发布,管理等包管理功能。

(3)Pip

Pip是目前包管理的事实标准。

构建在setuptools之上,替代easy_insall的,同样提供丰富的包管理功能。

 

(4)wheel

提供bdist_wheel作为setuptools的扩展命令,这个命令可以用来生成新打包格式wheel,

Pip开始提供了一个wheel子命令来安装wheel包,必须先安装wheel模块,让Python库以二进制形式安装,不需要再本地编译。

3、使用setup.py打包

首先创建一个setup.py文件,

内容:

from distutils.core import setup

setup(name=’3′,
version=’0.1.1′,
description = ‘test’,
author=’wcl’,
author_email=’www.qq.com’,
packages = [‘3’]
)
#name:名字
# version 版本
# packages=[]打包列表
# packages = [‘3’]指定以后,就会把所有的非目录子模块打包。
# [‘m’,’m.m1.m2.m3′] 逐级建立目录,但是只是把m的所有非目录子模块打包。后面的也打包
#description 描述信息
#author 作者
#author_email作者邮件
#url 包的主页,可以不写

 

查询帮助命令:Python setup.py cmd -help

4、build命令、编译

创建一个build目录

#Python setup.py build

 

在项目目录下多了build目录,有一个lib子目录,lib下就是模块m的目录。

所有的.py 文件全部被复制了,但是子目录没有被复制。

 

构建了同样的目录结构,并只是拷贝了__init__.py 文件。

 

build 得到的文件,直接拷贝到其他项目就可以使用了。

 

打包的时候子包不要,模块还是要带上的。  setup.build。Packages后面写的是包名,而不是模块名。

5、install命令,安装

Build后就可以install,直接运行

###Python setup.py install

如果没有build,会先build编译,然后安装。

 

6、sdist命令,分发

Sdist命令:

####Python setup.py sdist

创建源代码的分发包

产生一个dist目录,里面生成一个带版本号的压缩包。

在其他地方解压缩文件,里面有setup.py 就可以直接使用 Python setup.py install 安装了,也可以 ##pip install xxxxxxxxxxx 直接使用pip安装这个压缩包。

 

 

制作window是下的分发包:Python setup.py bdist_wininst.

打包成rpm:Python setup.Py bdist_rpm

 

也可以将写好的模块发布到公共的pipy上,也可以搭建pypi私服。

模块名前后:优先级。

7、wheel包

安装wheel依赖

## pip install wheel

from distutils.core import setup
from setuptools import setup
setup(name=’3′,
version=’0.1.1′,
description = ‘test’,
author=’wcl’,
author_email=’www.qq.com’,
packages = [‘3’]
)

分发一下,元代码打包成zip包。

 

 

 

 

 

 

 

 

四、插件化开发

动态导入

运行时候,根据用户需求(提供字符串),找到模块的资源动态加载起来。

1、__import__()内建函数

__import__ (name,globals=None,locals = None,fromlist=(),level=0)

Name模块名

Import语句本质上就是调用这个函数,但是不鼓励其直接使用,使用importlib.import_module().

Sys = _import__(‘sys’)

 

M2模块:

class A:
def show(self):
print(‘A’)

 

 

M1:模块

if __name__ == ‘__main__’:
mod = __import__(‘m2′)
cls = getattr(mod,’A’)
cls().show()

动态的调用

 

 

 

 

2、importlib.import_module()

 

class A:
def show(self):
print(‘A’)

 

import importlib
def load(name:str,sep=’.’):
m,_,c = name.partition(sep)
mod = importlib.import_module(m)
cls = getattr(mod,c)
return cls()

if __name__ == ‘__main__’:
a = load(‘m2.A’)
a.show()

 

A

插件化的核心代码。

3、插件化编程技术

依赖的技术

反射:运行时候获取类型的信息,可以动态维护类型数据。

动态import:推荐使用importlib模块,实现动态import模块的能力。

多线程:可以开启一个线程。等待用户输入,从而加载指定名称的模块。

 

 

4、加载的时机

1)程序启动时候。启动时候扫描固定的目录,加载插件。

2)程序运行时。程序运行中,接受用户指令或请求,启动相应的插件。

 

两个方式各有利弊,如果插件过多,会导致程序启动很慢,如果用户使用时候在加载,如果插件太大或者依赖多,插件将会启动慢。

所以先加载常用的,必须的插件,其他插件使用时候,发现需要,动态载入。

 

5、应用

软件的设计不可能尽善尽美,或者在某些功能上,不可能做的太专业了,需要专业的客户自己增强。

 

 

接口和插件的区别:

接口往往是暴露出来的功能。例如模块提供的函数或方法,加载模块后调用这些函数完成功能。接口也是一种规范,约定了必须实现的功能(必须提供某名称的函数),但是不关心怎么实现这个功能。

 

插件是吧模块加载到系统中,运行它,增强当前系统功能,或者提供系统不具备的功能,

往往插件技术应用在框架设计中,系统本身设计简单化,轻量级,实现基本功能后,其他功能通过插件加入进来,方便扩展。

 

五、基础知识补充的

1、__slots__

 

问题的引出

字典为了提升查询效率,必须利用空间换时间。

一般来说一个对象,属性多一点,都存储在字典中便于查询,问题不大。

对象数百万个。字典占用率就有些大了。

 

只要slots定义的,就会阻止了实例的字典,没有了字典,里面只能出现定义的属性,没有定义的一律不能使用。

class A:
X = 1
__slots__ = (‘x’,’y’)

def __init__(self,x,y):
self.x = x
self.y = y

def show(self):
print(self.x,self.y)

a = A(1,2)
a.show()

print(‘A’,A.__dict__)
# print(a.__dict__)  #字典被省略了
print(a.__slots__)

 

1 2

A {‘y’: <member ‘y’ of ‘A’ objects>, ‘show’: <function A.show at 0x000000972DAF4BF8>, ‘__init__’: <function A.__init__ at 0x000000972DAF4D08>, ‘__doc__’: None, ‘x’: <member ‘x’ of ‘A’ objects>, ‘__slots__’: (‘x’, ‘y’), ‘X’: 1, ‘__module__’: ‘__main__’}

(‘x’, ‘y’)

 

__slota__告诉解释器,实例的属性豆角什么,一般来说,既要节约内存,最好还是使用元组比较好。

 

而且实例不可以动态增加属性,类直接增加,因为__slots__是针对实例的。

 

只能限制当前类的实例,不能继承使用。除非子类里面自己也是定义了__slots__.

 

__slots__ = 后面写元组比较好。

 

 

 

应用场景:

使用需要构建在数百万以上的对象,且内存容量较为紧张,实例的属性检查、固定缺不用动态增加的场景。

 

2、未实现和未实现异常

1)NotImplemented  未实现。是个值,单值。

2)NotImplementedError    未实现异常。

3)只有raise才是无参数的构造。

print(type(NotImplemented))
print(type(NotImplementedError))
# raise NotImplemented   #不可以使用,显示的是不属于异常类
raise NotImplementedError

 

 

 

 

3、运算符重载中的反向方法

class A:
def __init__(self,x):
self.x = x

def __add__(self, other):
print(self,’add’)
return self.x + other.x

def __iadd__(self, other):
print(self,’iadd’)
return A(self.x + other.x)

def __radd__(self, other):
print(self,’radd’)
try:
return self.x + other.x
except AttributeError:
try:
x = int(other)
except:
x= 0
return self.x + x

a = A(4)
# b = A(5)
1 + a

 

 

执行__radd__,实现1+a的方法。

字符串也是实现了__add__ 方法,不过默认处理不了和其他类型的加法,所以就返回NotImplemented。

 

 

 

 

 

 

 

 

 

 

 

六、Git服务搭建

 

GIT

Gogs

Go语言开发的Git服务器。

 

 

MySQL安装。

  • 传文件。
  • 解包tar xf Percona-Server-5.5.45-37.4-r042e02b-el6-x86_64-bundle.tar
  • 安装 yum install Percona-Server-shared-55-5.5.45-rel37.4.el6.x86_64.rpm  Percona-Server-server-55-5.5.45-rel37.4.el6.x86_64.rpm Percona-Server-client-55-5.5.45-rel37.4.el6.x86_64.rpm
  • 检查:chkconfig   chkconfig mysql on
  • 启动service mysql start
  • 配置  mysql_secure_installation    (其中禁止root远程登录原则No其余全部是y)
  • ps anx |grep mysql  查看启动
  • 登录数据库mysql -uroot -p
  • 查看数据库 show database;

 

用户:

  • useradd git用户
  • 登录用户git
  • 传文件到git的家目录
  • tar xf gogs0.11.4_amd64.tar.gz   解包
  • Cd gogs文件夹
  • mkdir custom/conf -p  创建文件
  • cp ../app.ini ./custom/conf/   拷贝文件
  • 打开ini文件。

 

mysql登录:

  • rant all on gogs.* to ‘gogs’@’%’ identified by ‘gogs’;给文件授权
  • mysql -u gogs -p    利用gogs登录。

 

 

利用git用户登录

mysql -u root -p    和gogs是两套系统

 

 

mysql -u root -p

mysql -u root -p < gogs/scripts/mysql.sql   输入重定向。

mysql -u root -p

mysql> show databases;  重新查看。

use gogs   导入库。

show tables;   创建了数据库

 

 

退出到git gogs文件夹里面。

./gogs web 启动

 

 

 

 

启动服务:第二个窗口。

cd scripts/

 

cd init

cd centos

 

利用root账号拷贝文件:

cp /home/git/gogs/scripts/init/centos/gogs /etc/init.d

cd /etc/init.d

chmod +x gogs

[root@localhost init.d]# chkconfig gogs on

[root@localhost init.d]# chkconfig -list gogs

service gogs start  启动

创建log文件

[git@localhost centos]$ cd

[git@localhost ~]$ cd gogs

[git@localhost gogs]$

q启动

[root@localhost ~]# cd /etc/init.d

[root@localhost init.d]# service gogs start

Starting Gogs:

192.168.142.128:300连接

 

首次登陆:

进行安装程序,需要设置域名和应用URL。

点击立即安装,注册第一个用户,默认第一个用户为管理员账户。

创建一个仓库。

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/99009

发表评论

登录后才能评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1823388528@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班