python-05-01-列表解析_生成器_迭代器

  • 目录
  • 列表解析
  • 生成器
  • 迭代器

列表解析

什么是列表解析?
定义: 基于一个列表生成另外一个列表,或动态生成一个列表。
如:

1
2
3
4
5
In [26]: [ i ** 2 for i in range(2,8)]    # 对原列表乘以2
Out[26]: [4, 9, 16, 25, 36, 49]

In [25]: [ i for i in range(1,10) if i % 2 ] # 对原列表取奇数
Out[25]: [1, 3, 5, 7, 9]

练习1: 有如下文件

1
2
3
# cat word.txt
render practice inventory indent accelerate,
trigger status,wxq.

我们计算word.txt单词个数

1
2
3
4
5
6
7
8
9
10
11
In [29]: f = open('/root/word.txt', 'r')
In [31]: word_list = [ word for line in f for word in line.split() ]

In [36]: print(word_list)
['render', 'practice', 'inventory', 'indent', 'accelerate,', 'trigger', 'status,wxq.']

In [37]: f.seek(0) # 上面读取过文件,指针己然在最后了,这里是把指针移到文件首部
Out[37]: 0

In [38]: len([ word for line in f for word in line.split() ]) # 计算结果为7
Out[38]: 7

我们计算word.txt非空白字符数

1
2
3
4
5
In [37]: f.seek(0)       # 把指针移到文件首部
Out[37]: 0

In [41]: sum([ len(word) for line in f for word in line.split() ])
Out[41]: 58

练习2: 打印一个3行5列的矩阵

1
2
3
In [45]: list1 = [ (x+1, y+1) for x in range(3) for y in range(5) ]
In [47]: print(list1)
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5)]

练习3:

1
2
3
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']

练习4:

1
2
3
4
In [61]: L = ['I', 'WILL', 'STUDY', 'HARD', 'PYTHON']

In [62]: [ s.capitalize() for s in L ]
Out[62]: ['I', 'Will', 'Study', 'Hard', 'Python']

生成器

列表解析会创建完整列表占用内存,那么有没有一种算法或机制让我们循环使用时推算出后续元素,这样节省了内存空间。
定义:这种边循环边计算的机制,称为生成器generator

创建一个生成器,其中一个方法就是把前面的列表解析[] 换成()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [107]: g = (i for i in range(4))

In [108]: g
Out[108]: <generator object <genexpr> at 0x7f98a27ba150>

In [117]: g.send(None)
Out[117]: 0

In [118]: g.send(None)
Out[118]: 1

In [119]: next(g)
Out[119]: 2

In [120]: next(g)
Out[120]: 3

In [122]: next(g)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-122-5f315c5de15b> in <module>()
----> 1 next(g)

StopIteration:

利用yield创建一个生成器,取出完整元素需要用for 循环来迭代

1
2
3
4
5
6
7
8
9
10
11
In [123]: def genNum(x):
.....: i = 0
.....: while i < x:
.....: yield i
.....: i += 1

In [124]: g = genNum(5)
In [136]: for i in g:
.....: print(i, end=' ')
.....:
0 1 2 3 4

来看一下yield工作细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [138]: def consumer():
.....: print("yield starting")
.....: m = yield 5
.....: print("m_values: %s" % m)
.....: n = yield 12
.....: print("Game over")
.....:

In [139]: c = consumer()

In [140]: c.send(None)
yield starting
Out[140]: 5

In [141]: c.send('to be brave')
m_values: to be brave
Out[141]: 12

小结:

  • c.send(None)遇到第一个yield停止,在解释器中out yield中的值,在python yield.py却不会.
  • c.send(‘to be brave’)会上次中止处继续,’to be brave’会赋值给yield 5,即m = ‘to be brave’, 遇到第二个yield停止.
  • g.send(None)启动迭代器,遇到第一个yield返回.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    root@apt:~/script_study# cat yield.py 
    #!/usr/bin/env python3
    #
    def h():
    print("yield starting")
    m = yield 5
    print("m_values: %s" % m)
    d = yield 12
    print('Game over')
    c = h()
    # print test info
    c.send(None)
    c.send('Fighting!')

    root@apt:~/script_study# python3 yield.py
    yield starting
    m_values: Fighting!

后面协程正是用的这个知识点。

迭代器

细心的朋友不难发现生成器可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值为止。

  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
  • 可以直接作用于for循环的对象统称为可迭代对象:Iterable

哪些是可迭代对象呢?或说可作用于for循环呢?有以下几种数据类型:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

可以使用isinstance()判断一个对象是否是Iterable对象:

1
2
3
4
5
6
7
8
9
10
11
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

可以使用isinstance()判断一个对象是否是Iterator对象:

1
2
3
4
5
6
7
8
9
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

1
2
3
4
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

为什么list、dict、str等数据类型不是Iterator 呢?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
pass
实际上完全等价于:

1
2
3
4
5
6
7
8
9
10
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break

总结

1
2
3
4
5
6
7
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

迭代器:能够作用于next()函数,不断向后返回值,称为迭代器 iter([1,2,3,4])
生成器:yield返回,并且可以next(),是一种特殊的迭代器
可迭代对象:一个类中有__iter__()方法,并返回迭代器(包括生成器),那么这个类的对象就是可迭代对象,可for循环

web-01-开发入门

前言

从现在开始,此时此刻写点web开发Django 的知识,便于以后查阅学习。
廖雪峰老师的博客写得特别好,我也是摘抄参考其内容。
廖雪峰老师博客原文

一. HTTP协议简介

web历程

web开发经历几个阶段
1 静态页面: 直接由编辑器生成静态html
2 CGI: 交互与动态数据处理出现了CGI(common gateway interface),由C/C++编写
3 脚本语言(ASP/JSP/PHP): 脚本语言开发效率高,与html结合紧密
4 框架:mvc mtv mvvm

HTTP协议

服务器把网页传给浏览器,实际上就是把网页的html代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议就是HTTP

HTML是一种用来定义网页的文本,会HTML就会编写网页
http是在网络上传输html的协议,用于浏览器和服务器的通信

Elements显示网页的结构,Network显示浏览器和服务器的通信。我们点Network,确保第一个小红灯亮着,Chrome就会记录所有浏览器和服务器之间的通信。

GET / HTTP/1.1: 注:1.1版本允许多个HTTP请求复用一个TCP连接,以加快传输速度
浏览器就是依靠Content-Type来判断响应的内容是网页还是图片,是视频还是音乐

当浏览器读取到新浪首页的HTML源码后,它会解析HTML,显示页面,然后,根据HTML里面的各种链接,再发送HTTP请求给新浪服务器,拿到相应的图片、视频、Flash、JavaScript脚本、CSS等各种资源,最终显示出一个完整的页面。所以我们在Network下面能看到很多额外的HTTP请求。

HTTP请求流程

步骤1:
浏览器向服务器发送http请求
方法:GET仅请求资源 POST 会附带用户数据body部份
路径; /full/url/path
域名:

步骤2:
服务器向浏览器返回HTTP响应
响应代码:200表示成功 3** 表示重定向 4** 表示客户端发送的请求有错误 5** 表示服务器处理错误
响应类型: 由Content-Type指定
通常服务器的HTTP响应会携带内容,也就是有一个Body,包含响应的内容,网页的HTML源码就在Body中

步骤3:如果浏览器还需要继续向服务器请求其他资源,比如图片,就再次发出HTTP请求,重复步骤1、2

Web采用的HTTP协议采用了非常简单的请求-响应模式,从而大大简化了开发。当我们编写一个页面时,我们只需要在HTTP请求中把HTML发送出去,不需要考虑如何附带图片、视频等,浏览器如果需要请求图片和视频,它会发送另一个HTTP请求,因此,一个HTTP请求只处理一个资源

HTTP协议同时具备极强的扩展性,虽然浏览器请求的是http://www.sina.com.cn/的首页,但是新浪在HTML中可以链入其他服务器的资源,比如<img src="#url"/>,从而将请求压力分散到各个服务器上,并且一个站点可以链接到其他站点,无数个站点互相链接起来,就形成了World Wide Web,简称WWW。

二. HTML简介

HTML是一种用来定义网页的文本,会HTML就会编写网页 。
其它前端知识不在这里展开。略。。。

三 . WSGI接口

了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:
浏览器发送一个HTTP请求;
服务器收到请求,生成一个HTML文档;
服务器把HTML文档作为HTTP响应的Body发送给浏览器;
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。

这个接口就是WSGI:Web Server Gateway Interface。

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”:

1
2
3
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']

上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

environ:一个包含所有HTTP请求信息的dict对象;
start_response:一个发送HTTP响应的函数。

在application()函数中,调用:
start_response('200 OK', [('Content-Type', 'text/html')])
就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。

通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。
然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。

有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。

整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。

不过,等等,这个application()函数怎么调用?如果我们自己调用,两个参数environ和start_response我们没法提供,返回的bytes也没法发给浏览器。

所以application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。但是现在,我们只想尽快测试一下我们编写的application()函数真的可以把HTML输出到浏览器,所以,要赶紧找一个最简单的WSGI服务器,把我们的Web应用程序跑起来。

好消息是Python内置了一个WSGI服务器,这个模块叫wsgiref,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。

运行WSGI服务
我们先编写hello.py,实现Web应用程序的WSGI处理函数:

1
2
3
4
5
# hello.py

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']

然后,再编写一个server.py,负责启动WSGI服务器,加载application()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application

# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
确保以上两个文件在同一个目录下,然后在命令行输入python server.py来启动WSGI服务器:
python server.py 执行程序启动

四 web 框架

了解了WSGI框架,我们发现:其实一个Web App,就是写一个WSGI的处理函数,针对每个HTTP请求进行响应。

但是如何处理HTTP请求不是问题,问题是如何处理100个不同的URL。方法是一个函数处理一个URL, 我们专注于写业务处理函数,URL和函数对应关系交给web框架完成,这就是 web框架其中一个价值。

python-04-01-装饰器

  • 目录
  • 装饰器

Python装饰器,英文decorator, 以被装饰函数作为参数对其装饰。这里会用到函数,我们可以像使用变量一样使用函数,函数有对象一致特性。

  • 函数可以被赋值给其它变量
  • 函数可以内部再定义函数
  • 函数可以作为参数传递给另外一个函数
  • 函数可以直接返回给外层函数

简单函数进行装饰

有这么一个函数

1
2
def hello():  
return 'hello world'

我们想在不修改原函数的情况下,让函数返回特定标签

1
2
3
4
def maketag(func):
def wrapper():
return "<h>" + func() + "</h>"
return wrapper

我们定义了一个函数maketag(),该函数有一个参数func,这个参数必须是一个函数,内部又定义了一个wrapper()函数,并直接返回给maketag()

1
2
3
>>> hello = maketag(hello)  # 将 hello 函数传给 maketag
>>> hello()
'<h>hello world</h>'

上面我们把最初hello函数传给maketag()函数并将返回赋值给变量hello,此时调用hello得到我们想要的结果。
注意: maketag()返回赋值给hello,hello函数本身还存在,但函数名引用己经变为了maketag返回函数的名称wrapper,不在是原来的hello,验证一下

1
2
3
4
5
6
7
In [6]: a = maketag(hello)
In [8]: a.__name__
Out[8]: 'wrapper'

In [9]: hello = maketag(hello)
In [10]: hello.__name__
Out[10]: 'wrapper'

总结一下:为了增强原函数hello的功能定义了一个maketag函数,它接收一个函数作为参数,maketag返回一个新的函数赋值给一个变量hello,然后hello可直接调用。

一般情况下,我们使用装饰器提供的 @ 语法糖(Syntactic Sugar)来简化上面的写法:

1
2
3
4
5
6
7
8
def maketag(func):
def wrapper():
return "<h>" + func() + "</h>"
return wrapper

@maketag
def hello():
return 'hello world'

像上面的情况,可以动态修改函数(或类)功能的函数就是装饰器。本质上,它是一个高阶函数,以被装饰的函数(比如上面的 hello)为参数,并返回一个包装后的函数(比如上面的 wrapper)给被装饰函数(hello)。

单/多个装饰器的使用形式

装饰器的一般使用形式如下:

1
2
3
4
5
6
7
8
@decorator
def func():
pass
等价于下面的形式:

def func():
pass
func = decorator(func)

装饰器可以定义多个,离函数定义最近的装饰器先被调用,比如:

1
2
3
4
5
6
7
8
9
10
@decorator_one
@decorator_two
def func():
pass
等价于:

def func():
pass

func = decorator_one(decorator_two(func))

看下多个装饰器的例子,为了简单起见,下面的例子就不使用带参数的装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def maketag1(func):
def wrapper():
return '<html>' + func() + '</html>'
return wrapper

def maketag2(func):
def wrapper():
return '<i>' + func() + '</i>'
return wrapper

@maketag1
@maketag2
def hello():
return 'hello world'

上面定义了两个装饰器,对 hello 进行装饰,上面的最后几行代码相当于:

1
2
3
4
5
6
7
8
def hello():
return 'hello world'

hello = maketag1(maketag2(hello))
调用函数 hello:

>>> hello()
'<html><i>hello world</i></html>'

似乎理解深刻了:当多个装饰器时,离函数定义最近的装饰器先被调用

对带参数的函数进行装饰

让被装饰函数带有参数,对前面例子中的 hello() 函数进行改写使其带参数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
def maketag(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return '<h>' + res + '</h>'
return wrapper

@maketag
def hello(name):
return 'hello %s' % name

@maketag
def hello2(name1='user1', name2='user2'):
return 'hello %s, %s' % (name1, name2)

由于函数 hello 带参数,因此内嵌包装函数 wrapper 也做了一点改变:

内嵌包装函数的参数传给了 func,即被装饰函数,也就是说内嵌包装函数的参数跟被装饰函数的参数对应,这里使用了 (*args, **kwargs),是为了适应可变参数。
看看使用:

1
2
3
4
>>> hello1('python')
'<h>hello python</h>'
>>> hello2('python', 'java')
'<h>hello python, java</h>'

带参数的装饰器

装饰器还可以带参数,比如:

1
2
3
4
5
6
7
8
9
@decorator(args1, args2)
def func():
pass
等价于:

def func():
pass

func = decorator(args1, args2)(func)

我们想改用标签 <html>...</html> 是不是要再定义一个装饰器呢?不必,其实我们可以装饰器外层再定义一个函数,将标签作为参数,返回一个装饰器,比如:

1
2
3
4
5
6
7
8
def outer_decorator(tag):     # 外层函数参数传给装饰器
def decorator(func): # 真正的装饰器参数必然是被装饰器函数func
def wrapper(*args, **kwargs): # 装饰器内层函数的参数是func的参数
res = func(*args, **kwargs) # 被装饰函数正常调用
# return '<' + tag + '>' + res + '</' + tag + '>'
return '<{tag}>{res}</{tag}>'.format(tag=tag, res=res)
return wrapper # 内层函数作返回值返回给装饰器
return decorator # 装饰器本身作为返回值返回给最外层函数

现在,我们可以根据需要生成想要的装饰器了:

1
2
3
4
5
6
7
outer_decorator = outer_decorator('html')
@outer_decorator
def hello(name):
return 'hello %s' % name

>>> hello('world')
'<html>hello world</html>'

上面的形式也可以写得更加简洁:

1
2
3
@outer_decorator('html')     # @语法糖syntactic sugar
def hello(name):
return 'hello, %s' % name

这就是带参数的装饰器,其实就是在装饰器外面多了一层包装,根据不同的参数返回不同的装饰器。

基于类的装饰器

前面的装饰器都是一个函数,其实也可以基于类定义装饰器,看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Deco_C(object):
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
return '<html>' + self.func(*args, **kwargs) + '</html>'

@Deco_C
def hello(name):
return 'hello %s' % name

>>> hello('world')
'<html>hello world</html>'

可以看到,类 Deco_C 有两个方法:

__init__():它接收一个函数作为参数,也就是被装饰的函数
__call__():让类对象可调用,就像函数调用一样,在调用被装饰函数时被调用
还可以让类装饰器带参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Tag(object):
def __init__(self, tag):
self.tag = tag

def __call__(self, func):
def wrapper(*args, **kwargs):
return "<{tag}>{res}</{tag}>".format(res=func(*args, **kwargs), tag=self.tag)
return wrapper

@Tag('html')
def hello(name):
return 'hello %s' % name

>> hello(', welcome')
'<html>hello, welcome</html>'

需要注意的是,如果类装饰器有参数,则 init 接收此参数,而 call 接收 func函数,并多了一层wrapper(*args, **kwargs)来接收func函数的参数。

装饰器的副作用

前面提到装饰器有一个瑕疵,就是被装饰函数的函数名称已经不是原来的名称了,回到最开始的例子:

1
2
3
4
5
6
7
8
def maketagc(func):
def wrapper():
return "<i>" + func() + "</i>"
return wrapper

@maketag
def hello():
return 'hello world'

函数 hello 被 maketag 装饰后,它的函数名称已经改变了:

1
2
>>> hello.__name__
'wrapper'

为了消除这样的副作用,Python 中的 functool 包提供了一个 wraps 的装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from functools import wraps

def maketag(func):
@wraps(func) # 加上 wraps 装饰器
def wrapper():
return "<i>" + func() + "</i>"
return wrapper

@maketag
def hello():
return 'hello world'

>>> hello.__name__
'hello'

小结:
本质上,装饰器就是一个有返回函数的高阶函数。
装饰器可以动态地修改一个类或函数的功能,通过在原有的类或者函数上包裹一层修饰类或修饰函数实现。
事实上,装饰器就是闭包的一种应用,但它比较特别,以被装饰函数为参数,并返回一个函数,赋给被装饰函数,闭包则没这种限制。

装饰器生产化进阶

eg1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def deco(func):
def wrapper(x):
print("what ...")
func(x)
print('Game over ...')
return wrapper

@deco
def show(x):
print(x)
>>>show("I am a pythoner")
what ...
I am a pythoner
Game over ...

eg2:

shell getopts语法

Linux shell中getopts语法是一个很高级的语法,它能让你写出很漂亮的shell,来看个例子学习下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
root@ubuntu:~# cat getopts.sh 
#!/bin/bash
# a: b: c: 表示脚本运行时接受选项<-a options_1> <-b options_2> <-c options_3>
# first: 表示友好, 给出错误选项时尽量少的打印错误信息
# OPTARG 表示选项给的值
# OPTIND 表示选项指针(下一位)
# 比如:(-a 指针为2) (-a a1 -b 指针为4) (-a a1 -b b1 -c c1指针为7)

while getopts ":a:b:c:" OPT;
do
case $OPT in
a)
echo "a is OPTARG: $OPTARG"
echo "a is OPTIND: $OPTIND"
;;
b)
echo "b is OPTARG: $OPTARG"
echo "b is OPTIND: $OPTIND"
;;
c)
echo "c is OPTARG: $OPTARG"
echo "c is OPTIND: $OPTIND"
;;
*)
echo "Usage: $0 [-a arg1] [-b arg2] [-c arg3]"
esac
done
shift $(($OPTIND-1))
echo "\$1 is: $1"
root@ubuntu:~# bash getopts.sh -a a1 -b b1 -c c1 test.sh
a is OPTARG: a1
a is OPTIND: 3
b is OPTARG: b1
b is OPTIND: 5
c is OPTARG: c1
c is OPTIND: 7
$1 is: test.sh

Mysql 基础篇

  • 目录
  • 知识扫盲
  • 基础语句
  • 主键、外键
  • 修改表
  • 分组与聚合
  • 连表查询
  • 其它查询
  • shell终端获取数据

数据库操作无非就是insert`deleteupdateselete,这篇博客对mysql`数据库语句做个总结记录便于学习

  • 知识扫盲

什么是事务: 原子性操作(不可拆分)就是要么全成功,要么全失败。

mysql语句的注释符是 --,在SQL注入或别的场景中语句形如:username=”root” and 1 =1 – and password=’123’
很明显 username="root" and 1 =1将永远成立, and password=’123’ 部份将被注释,这点需要注意。

基础语句

基础语句过于简单,这里就简单逻列下。

创建数据库

1
CREATE DATABASE db1 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

创建一张表
注意:auto_increment表示自增,primary key 表示id 这列为主键
default charset utf8指定默认字符集
engine=innodb指定因默认引警

1
2
3
4
create table tb1(
id int not null auto_increment primary key,
name char(20) not null,
age int) engine=innodb default charset utf8;

插入数据

1
insert into tb1(name,age) values('wxq',20),('pp',18);

更改数据

1
update tb1 set age=25  where name='wxq';

删除某条数据

1
delete from tb1 where id>1;

删除表内所有数据

1
2
delete from 表名      # 不会删除自增序列
truncate table 表名 # 会删除自增序列,再次插入数据将从0开始,删除更辙底

删除表

1
drop table tb1

主键

1
2
3
4
5
主键
create table tb1(
id int not null auto_increment primary key,
name char(20) not null,
age int) engine=innodb default charset utf8;
1
2
3
4
5
6
组合主键
create table tb1(
nid int not null,
num int not null,
primary key(nid,num)
)

外键

1
constraint fk_任意字符 foreign key (department_id自己字段) references  department外面的表(nid外面表的字段)
1
2
3
4
5
6
7
8
外键(约束):一对多
create table tb1(
id int not null primary key,
name char(32) null ,
age int not null,
department_id int not null
constraint fk_department_nid foreign key (department_id) references department(nid)
)

双向外键(约束):多对对
创建主机与部门之间的多对多关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
create table host (
id int not null auto_increatement primary key,
host char(20) not null );

create table department(
id int not null auto_increatement primary key,
title char(20) not null
);

create table de_2_host (
id int not null auto_increatement primary key,
hid int not null,
did int not null,
constraint fk_hid_host foreign key (hid) references host(id),
constraint fk_did_department foreign key (did) references department(id)
)

修改表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
添加列:alter table 表名 add 列名 类型
删除列:alter table 表名 drop column 列名
修改列:
alter table 表名 modify column 列名 类型; -- 类型
alter table 表名 change 原列名 新列名 类型; -- 列名,类型

添加主键:
alter table 表名 add primary key(列名);
删除主键:
alter table 表名 drop primary key;
alter table 表名 modify 列名 int, drop primary key;

添加外键:alter table 从表 add constraint 外键名称(形如:FK_从表_主表) foreign key 从表(外键字段) references 主表(主键字段);
删除外键:alter table 表名 drop foreign key 外键名称

修改默认值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000;
删除默认值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT;
1
2
3
4
show variables like '%char%';       查看整个mysql字符集
show create table migrate_version; 查看表字符集
alter table migrate_version character set utf8; 设置表字符集或者如下条:
alter table migrate_version default character set utf8 collate utf8_general_ci;

分组与聚合

group by

- 对列进行聚合 sum(sid),max(sid),min(sid),count(sid)
- 聚合条件过滤,having count(sid) > 7
1
2
3
4
5
6
7
8
9
分组
select num from 表 group by num
select num,nid from 表 group by num,nid
select num,nid from 表 where nid > 10 group by num,nid order nid desc
select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid

select num from 表 group by num having max(id) > 10

特别的:group by 必须在where之后,order by之前

连表查询

示例

1
2
3
4
select  A.sid,A.sname,B.caption
from student as A
left join class as B
on A.class_id = class.cid;

  • left join 表名 on 多出的数据将会出现NULL数据
  • rigth join 表名 on 相对left 只是表位置变化,其它没有区别
  • inner join 表名 on 不会出现NULL数据,没有关联的数据将不会显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
连表
无对应关系则不显示
select A.num, A.name, B.name
from A,B
Where A.nid = B.nid

无对应关系则不显示
select A.num, A.name, B.name
from A inner join B
on A.nid = B.nid

A表所有显示,如果B中无对应关系,则值为null
select A.num, A.name, B.name
from A left join B
on A.nid = B.nid

B表所有显示,如果B中无对应关系,则值为null
select A.num, A.name, B.name
from A right join B
on A.nid = B.nid

其它查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
a、条件
select * from 表 where id > 1 and name != 'wxq' and num = 12;

select * from 表 where id between 5 and 16;

select * from 表 where id in (11,22,33)
select * from 表 where id not in (11,22,33)
select distinct name from 表 where id in (select nid from 表) # distinct重复数所将只显示一条

b、通配符
select * from 表 where name like 'wxq%' - wxq开头的所有(多个字符串)
select * from 表 where name like 'wx_' - wx开头的所有(一个字符)

c、限制
select * from 表 limit 5; - 前5行
select * from 表 limit 4,5; - 从第4行开始的5行
select * from 表 limit 5 offset 4 - 从第4行开始的5行

d、排序
select * from 表 order by 列 asc - 根据 “列” 从小到大排列
select * from 表 order by 列 desc - 根据 “列” 从大到小排列
select * from 表 order by 列1 desc,列2 asc - 根据 “列1” 从大到小排列,如果相同则按列2从小到大排序

e、组合
组合,自动处理重合
select nickname
from A
union
select name
from B

组合,不处理重合
select nickname
from A
union all
select name
from B

shell终端获取数据

下面介绍在shell终端获取mysql的几种方法

用法一:

1
2
3
4
5
6
[root@mysql ~]# mysql -p123 -e "show global status where variable_name='uptime'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Uptime | 8025 |
+---------------+-------+

用法二:

1
2
3
4
[root@mysql ~]# mysql -p123 -N -e "show global status where variable_name='uptime'"
+--------+------+
| Uptime | 8029 |
+--------+------+

用法三:

1
2
[root@mysql ~]# mysql -p123 -s -N -e "show global status where variable_name='uptime'"
Uptime 8037

用法四:

1
2
[root@mysql ~]# echo "show global status where variable_name='uptime';" | mysql -N -p123
Uptime 8072

1
2
3
4
5
6
7
8
9
# echo  "show databases;" | mysql -h 127.0.0.1 -uroot -A -p123 | tail -n +2  | head -n 2
-A 表示不自动rehash
tail -n +2 表示从第二行开始打印
head -n 2表示打印前2行

# echo "use nova01 ; show tables;" | mysql -uroot -padmin
# mysql -uroot -padmin -S /var/run/mysqld/mysqld.sock -e "use nova01;show tables;"
# mysql -uroot -padmin -S /var/run/mysqld/mysqld.sock \
-e "grant all on *.* to user1@'localhost' identified by \"user1\";"

该操作会在用户家目录下生成一个隐藏文件”.mylogin.cnf”,里面记录了MYSQL的密文的密码,只要配置了以后,我们也是直接使用命令登录,再也无需输入账号密码了,如果你想取消,删除此文件即可。

1
mysql_config_editor set --user=root --host=localhost --port=3306 --password

python-03-02-函数

  • 目录
  • 函数概念
  • 普通函数
  • 匿名函数
  • 递归函数
  • 闭包
  • 高阶函数

函数概念

什么是函数

  • 函数是python为了代码最大程度地重用和最小化代码冗余而提供的基本程序结构
  • 函数是一种设计工具,它能让程序员将复杂的程序逻辑分解为可管理的部件
  • 函数用于将相关功能打包并参数化,一个函数可以当参数传给变量或另一个函数
  • python自带有许多内置函数
  • 在python有4种函数表现形式:
    1
    2
    3
    4
    全局函数: 定义在模块中
    局部函数:嵌套于其它函数中
    lambda函数:表达式,可以出现在任意表达式可以出现的地方(又称匿名函名)
    方法:定义在类中与特定数据类型关联的函数,并且只能与数据类型关联一起使用.

函数语法

  • 函数代码表现
    1
    2
    def functionName(parameters):
    函数主体代码

相关概念

def 是一个可执行语句,因此可以出现在任意语句可以出现的地方,甚至可以嵌套于其它if/while语句中
def 创建了一个对象并将其赋值给一个变量名,也就是函数名
return 用于返回结果对象,其为可选,无return语句时函数自动返回None对象,多个返回值时用逗号分隔,并组合为元组形式返回一个对象
def 语句运行之后可以在程序中通过函数后附加括号的形式进行调用

普通函数

函数传参
内置函数
官方 详解
More info 动我试试

Built-in Functions
abs() dict() help() main() setattr()
all() dir() hex() next() slice()
any() divmod() id() object() sorted()
ascii() enumerate() input() oct() staticmethod()
bin() eval() int() open() str()
bool() exec() isinstance() ord () sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()
delattr() hash() memoryview() set()

拿几个作下说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ASCII编码表查询:
ord('a') 字符在编码表中的数字表示
chr(97) 数字在编码表中的字符表示

global() 查看全局变量
locals() 查看局部变量
vars() 无参数时等于locals(), 有参数时vars(a) == a.__dict__ (__dict__一个对象的属性)

eval() 把字符串形式的表达式解析并扫行
exec() 把字符串形式的代码解析并执行
compile()把文件的代码加载进来,按 eval, exec方式解析并执行

# 以字符串的形式导入模块, 后面模块章节也会讲到__import__()用法
mode = 'module_name'
__import__(mode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
all()与any()区别:
all:
传入一个可迭代对象,对其中每个元素求bool(x),所有返回True,则返回Tru
迭代对象为空时返回True,注意是为空如[],不是空元素如['']

any:
传入一个可迭代对象,对其中每个元素求bool(x),任意一个返回True,则返回True
迭代对象为空时,返回False

def all(*args, **kwargs): # real signature unknown
"""
Return True if bool(x) is True for all values x in the iterable.

If the iterable is empty, return True.
"""
pass

def any(*args, **kwargs): # real signature unknown
"""
Return True if bool(x) is True for any x in the iterable.

If the iterable is empty, return False.
"""
pass

匿名函数

1
2
3
In [31]: f = (lambda x,y,z=10: x+y+z)       # 匿名函数也支持默认参数   
In [32]: f(4,9)
Out[32]: 23
1
2
3
4
5
6
In [56]: L = [ (lambda x: x*2),(lambda y: y*3) ]    # 匿名函数可以出现在任意表达式可以出现的地方
In [56]: for i in L:
....: print(i(4))
....:
8
12

递归函数

定义: 一个函数的自我循环调用称为递归

  • 阶乘

    1
    2
    3
    4
    5
    6
    >>> def fact(x):
    ... if x <= 1: return 1
    ... else: return x * fact(x-1)
    ...
    >>> fact(4)
    24
  • 汉诺塔
    汉诺塔: 是一个传说,大概意思就是说把一个柱子上的盘子通过第二根柱子移到第三根柱子上。。未完。。。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    root@ubuntu:~# cat  hanoi.py 
    #!/usr/bin/env python3

    def move(n, a, b, c):
    if n == 1:
    print('move', a, '-->', c)
    else:
    move(n-1, a, c, b)
    print('move', a, '-->', c)
    move(n-1, b, a, c)
    n = int(input("input: "))
    move(n, 'A', 'B', 'C')
    root@ubuntu:~# python3 hanoi.py
    input: 3
    move A --> C
    move A --> B
    move C --> B
    move A --> C
    move B --> A
    move B --> C
    move A --> C
  • 斐波那契数列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    root@ubuntu:~# cat fibonacci.py 
    #!/usr/bin/env python3

    def fibonacci():
    a = b = 1
    yield a
    yield b
    while True:
    a, b = b, a+b
    yield b
    for num in fibonacci():
    if num > 100:
    break
    print(num, end=' ')

    print()
    root@ubuntu:~# python3 fibonacci.py
    1 1 2 3 5 8 13 21 34 55 89

闭包

python闭包:lexical closure
函数及相关环境所构成的整体, 或者说一个函数(内层函数)和它所处的环境(外层函数)所构成的整体称为python闭包
在这种情况下内层函数会记住外层函数的变量,在外层函数返回时内层函数依然可以调用

eg1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [123]: def f1(x):
.....: def f2(y):
.....: return y ** x
.....: return f2 # 内层函数直接返回
.....:
In [124]: f = f1(3) # f1为f2提供运行环境,记住外部变量

In [125]: f
Out[125]: <function __main__.f1.<locals>.f2>

In [126]: f(4)
Out[126]: 64

In [127]: f(5)
Out[127]: 125

以上例子用匿名函数lambda简写成如下

1
2
3
4
5
6
7
8
In [129]: def f1(x):
.....: return lambda y: y ** x
.....:

In [131]: f = f1(3)

In [132]: f(6)
Out[132]: 216

高阶函数

定义: 一个函数当参数传递给另一个函数,我们就称这样的函数为高阶函数.
装饰器/函数闭包: 是有返回函数的高阶函数,是高阶函数的特例

高阶函数 用法说明
map(func,seq1,seq2) 将函数func作用于给定序列(s)的每个元素,并用一个列表来提供返回值,如果func为None,func表现为一个身份函数,返回一个含有每个序列中元素集合的n个元组列表
reduce(func, seq, init) 将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列无素),连续地将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值,如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素
filter(func,seq) 调用一个布尔函数func来迭代遍历每个seq中的元素,返回一个使func返回值为True的元素组成的序列

map()

map()将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回

一个序列时

1
2
3
4
5
6
7
In [143]: def f(x):
.....: return x ** 2

In [144]: res = map(f, [1,2,3,4]) # 根据说明这里返回结果是一个Iterator惰性序列

In [145]: list(res) # 惰性序列需要通过list()函数让它把整个序列都计算出来并返回一个list
Out[145]: [1, 4, 9, 16]

二个序列时
每一次同时依次取一个序列的一个值,两个序列就有2个值,那么用传入的函数作用于这2个值返回一个值,最后这些值再以列表显现。

1
2
3
4
5
6
7
In [140]: def f(x,y):
return y ** x

In [141]: res = map(f, [1,2,3], [4,5,6])

In [142]: list(res)
Out[142]: [4, 25, 216]

reduce()

python3中reduce函数在functools模块里,用时需要先导入

从初始值开始,对序列折叠

1
2
3
4
5
6
In [39]: from functools import reduce
In [50]: def add(x,y):
....: return x+y
....:
In [52]: reduce(add, [1,2,3], 10) # 10为初始值
Out[52]: 16

如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:

1
2
3
4
5
6
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579

这个例子本身没多大用处,但是考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map()就可以写出把str转换为int的函数:

1
2
3
4
5
6
7
8
9
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> def char2num(s):
... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
...
>>> reduce(fn, map(char2num, '13579'))
13579

整理成一个str2int的函数就是:

1
2
3
4
5
6
7
8
from functools import reduce

def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
return reduce(fn, map(char2num, s))

还可以用lambda函数进一步简化成:

1
2
3
4
5
6
7
from functools import reduce

def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]

def str2int(s):
return reduce(lambda x, y: x * 10 + y, map(char2num, s))

也就是说,假设Python没有提供int()函数,你完全可以自己写一个把字符串转化为整数的函数.

filter()

Python内建的filter()函数用于过滤序列。
filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

1
2
3
4
5
def is_odd(n):
return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]

把一个序列中的空字符串删掉,可以这么写:

1
2
3
4
5
def not_empty(s):
return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 结果: ['A', 'B', 'C']

可见filter()这个高阶函数,关键在于正确实现一个“筛选”函数, 这个函数必须是一个二元函数,返回TrueFalse的函数

注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

用filter求素数

计算素数的一个方法是埃氏筛法,它的算法理解起来非常简单:

首先,列出从2开始的所有自然数,构造一个序列:

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
不断筛下去,就可以得到所有的素数。

用Python来实现这个算法,可以先构造一个从3开始的奇数序列:

1
2
3
4
5
def _odd_iter():
n = 1
while True:
n = n + 2
yield n

注意这是一个生成器,并且是一个无限序列。

然后定义一个筛选函数:

1
2
def _not_divisible(n):
return lambda x: x % n != 0

最后,定义一个生成器,不断返回下一个素数:

1
2
3
4
5
6
7
def primes():
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it) # 返回序列的第一个数
yield n
it = filter(_not_divisible(n), it) # 构造新序列

这个生成器先返回第一个素数2,然后,利用filter()不断产生筛选后的新的序列。

由于primes()也是一个无限序列,所以调用时需要设置一个退出循环的条件:

1
2
3
4
5
6
# 打印1000以内的素数:
for n in primes():
if n < 1000:
print(n)
else:
break

小结: filter()的作用是从一个序列中筛出符合条件的元素。由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。

sorted()

sorted()高阶函数用于排序

sorted()语法

1
2
sorted(iterable, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.

先来看一个例子:

1
2
3
4
5
6
>>> list1 = [{"age":20, "name": "def"}, {'age':25, "name":"abc"}, {"age":10, "name":"ghi"}]

>>> sorted(list1, key=lambda x: x['age'], reverse=False)
[{'age': 10, 'name': 'ghi'},
{'age': 20, 'name': 'def'},
{'age': 25, 'name': 'abc'}]

这个例子也可以写成:

1
2
3
4
5
6
7
8
9
10
In [174]: def f1(x):
.....: return x["age"]
.....:
In [175]: list1 = [{"age":20, "name": "def"}, {'age':25, "name":"abc"}, {"age":10, "name":"ghi"}]

In [176]: sorted(list1, key=f1)
Out[176]:
[{'age': 10, 'name': 'ghi'},
{'age': 20, 'name': 'def'},
{'age': 25, 'name': 'abc'}]

list1这样的迭代对象取出一个值(一个一个的字典)给key函数处理后的结果作为排序依据,而后返回另一个排续后的对象.

列表自身有个sort()方法,和sorted()有什么区别呢? 来看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
In [66]: list1
Out[66]: [1, 2, 3, 4, 5]

In [67]: list1.sort() # sort()方法是在原有列表上排序,这是与sorted()高阶函数的区别

In [68]: list1
Out[68]: [1, 2, 3, 4, 5]

In [69]: list1.sort(reverse=True) # reverse表示逆序

In [70]: list1
Out[70]: [5, 4, 3, 2, 1]

区别就是sorted()会生成新的对象,而列表sort()不会,如下是按字母排序的例子:

1
2
In [173]: sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
Out[173]: ['about', 'bob', 'Credit', 'Zoo']

python-03-01-IO

  • 目录
  • 文件对象
  • OS 对象

IO 编程

文件对象

文件对象用于访问系统文件的接口,文件系统是计算机存储数据,组织数据的方式。
计算机文件是存储在设备中的一段数据流,归属于文件系统管理之下。是计算机中由OS管理的具有名字的存储区域,对Linux而言,文件可以被看作字节序列。

序列化的对象才能存储的文件系统中,非字节序列化的数据不能存储在文件系统中的。

文件对象接口不仅用于访问普通文件,还可以访问套接字文件,管道文件。
在Python中,文件读写是通过open()函数打开的文件对象完成的。使用with语句操作文件IO是个好习惯。

open(name[,mode[,bufsize]]) 返回的是一个文件对象。这里三个参数分别表示文件名,文件打开模式和缓冲区大小

bufsize:定义输出缓存

1
2
3
4
0 表示无输出缓存,禁用缓冲
1 表示使用缓冲,只缓冲一行数据
负数表示使用系统默认设置
2+之后的正数表示使用指定大小缓冲

open(‘/var/log/message’, ‘r’)
简单模式,首次打开的文件指针于文件首部
r: 只读
w: 新建文件或文件首部覆盖写入。
a: 尾部追加,即打开时指针处于文件尾部

在模式后使用+表示同时支输入输出操作
r+ w+ a+

在模式后附加 b 表示二进制方式打开
rb wb+

创建一个文件对象

1
2
3
>> f = open('/etc/fstab', 'r')
In [3]: type(f)
Out[3]: _io.TextIOWrapper

只读模式打开一个不存在文件是不可以的

1
2
3
4
5
6
7
In [1]: f = open('/tmp/abc', 'r')
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-1-07bb2dbd474f> in <module>()
----> 1 f = open('/tmp/abc', 'r')

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/abc'

以写模式打开一个不存在文件,这个文件会自动被创建

1
2
3
4
5
6
7
8
In [3]: import os
In [7]: os.path.isfile('/tmp/f1')
Out[7]: False

In [8]: f = open('/tmp/f1', 'w+')

In [9]: os.path.isfile('/tmp/f1')
Out[9]: True

查看一个文件的描述符,描述符是一个很小的数字表示,0表示标准输入,1表示标准输出,2表示标准错误输出它们所使用的描述符

1
2
In [20]: f.fileno()
Out[20]: 8

f.readline() 读文件一行数据
f.readlines() 读文件指针处至尾部所有数据包括行结束符\n,一行为一个对象,然后多行多个对象组成一个列表

返回指针在当前文件中的位置,表示在多少个字节的位置。

1
2
In [23]: f.tell()
Out[23]: 597

f.seek(offset, whence) offset:表示偏移多少个字节,whence表示从 多少节字数开始偏移。下面表示回到文件首部:

1
2
In [37]: f.seek(0)
Out[37]: 0

f.read() 读取给定字节

1
2
3
4
5
6
In [44]: f.seek(0)
Out[44]: 0
In [45]: f.read(10)
Out[45]: '# /etc/fst'
In [46]: f.tell()
Out[46]: 10

1
2
3
4
5
6
7
8
9
10
In [57]: f = open('/etc/fstab', 'r')
In [58]: f.name #返回文件名
Out[58]: '/etc/fstab'

In [59]: f.closed #返回是否关闭文件
Out[59]: False

In [60]: f.close() #关闭文件
In [61]: f.closed
Out[61]: True

操作完毕会自动关闭文件对象

1
2
with  open('/root/wxq.txt','w+') as  f:
f.write('hello world!\n')

OS 对象

一些方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
os.path   跟文件路径相关
basename() 路径基名
dirname() 路径目录名
join()
split() 返回dirname(), basename()元组
splitext() 返回(filename, extension_name)元组

信息:
getatime()
getctime()
getmtime()
getsize() 获取文件大小

查询:
exists() 指定文件是否存在
isabs() 指定路径是否为绝对路径
isdir() 是否为目录
isfile() 是否为文件
islink() 是否为符号链接
ismount() 是否为挂载点
samefile() 两个路径是否指向了同一个文件

__file__属性

在上面的glabals()中有一个file属性,其中保存的是程序运行的相对路径,
如python3 ../py3_training/test/yy.py,则路径为../py3_training/test/yy.py
在pycharm中为什么又变成了绝对路径了呢,不要认为是pycharm做了封装,是因为pycharm运行路径永远从c:\开始,这样看不出效果

要获取程序绝对路径os.path.abspath(file)
应用举例:

1
2
3
4
5
6
7
8
9
10
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)

from core import main

if __name__ == '__main__':
main.run()

来几个小练习,似乎参悟了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> import os
>>> os.path.split('/root/wxq.txt')
('/root', 'wxq.txt')
>>> os.path.splitext('/root/wxq.txt')
('/root/wxq', '.txt')
>>> os.path.dirname('/root/wxq.txt')
'/root'
>>> os.path.basename('/root/wxq.txt')
'wxq.txt'
>>> dir, file_name = os.path.split('/root/wxq.txt')
>>> dir
'/root'
>>> file_name
'wxq.txt'

python_02_流程控制/枚举

  • 目录
  • 流程控制
  • 三元表达式
  • 枚举类

流程控制

if

if 玩猜数字游戏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
i = 0
try_num = 3
AGE = 27
while i < try_num:
enter = int(input('enter you num:'))
if enter == AGE:
print("Conguratulations, you got it")
break
elif enter > AGE:
print("too large")
i += 1
else:
print("too smaller")
i+=1

if成绩查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
__author__ = "wxq"

enter_score = int(input("enter your score :").strip())

if enter_score <=100 and enter_score >=0:
if enter_score >=90:
print("A")
elif enter_score >=80:
print("B")
elif enter_score >=70:
print("C")
elif enter_score >= 60:
print("D")
else:
print("you are too low")

else:
print("invalid score")

while

这里主要注意与shell中的区别,python里while后有else, 即while语句正常执行完后才执行else中的语句,否则不会执行。

1
2
3
4
5
6
7
8
9
10
11
i = 0
while i <3:
if i >=2:
break
print(i)
i += 1
else:
print('end')
#结果
0
1

来个小练习

1
2
3
4
5
6
7
8
9
10
11
12
13
count1 = 0
while True:
if count1 == 10000000:
break
count1 += 1
print("cost", time.time() - t1_start, count1)


t2_start = time.time()
count2 = 0
while count2 < 10000000:
count2 += 1
print("cose", time.time() - t2_start, count2)

for

很懒什么也没有留下…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
count = 3
AGE = 27
for i in range(100):
if i >3:
enter=input("are you want to keep trying ....").strip()
if enter == "y":
count = 0
else:
break

enter = int(input('enter you num:'))
if enter == AGE:
print("Conguratulations, you got it")
break
elif enter > AGE:
print("too large")
else:
print("too smaller")

count +=1

continue/break

continue结束本次循环,提前进入下一轮循环
break 直接终止循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python3
__author__ = "wangxiaoqiang"

for i in range(10):
if i == 5:
for j in range(10):
if j == 8:
break
print("inner loop",j)
continue
print("loop",i)
结果:
loop 0
loop 1
loop 2
loop 3
loop 4
inner loop 0
inner loop 1
inner loop 2
inner loop 3
inner loop 4
inner loop 5
inner loop 6
inner loop 7
loop 6
loop 7
loop 8
loop 9

三元表达式

三元表达式很简单, 这里来几个小例子就明白了

条件满足为1,否则为False

1
2
n [44]: 1 if True else False
Out[44]: 1

成员关系判断,条件满足为True, 否则为False

1
2
3
4
5
In [53]: True if 1 in [1,2,3] else False
Out[53]: True

In [54]: True if 0 in [1,2,3] else False
Out[54]: False

1
2
3
4
5
In [45]: a = 10
In [46]: b = 15

In [47]: a if a>b else b
Out[47]: 15

枚举类

枚举 enumerate, 在用到index和value对应关系时能用到enumerate函数,参数为可遍历对象(字符串,列表等),返回多个元组

1
2
3
4
5
6
7
8
9
10
11
12
In [3]: for i in enumerate('abc'):
...: print(i)
...:
(0, 'a')
(1, 'b')
(2, 'c')
In [43]: for index,i in enumerate('abc', 10):
....: print(index,i)
....:
10 a
11 b
12 c

1
2
3
4
In [4]: a = enumerate('abc')

In [5]: list(a)
Out[5]: [(0, 'a'), (1, 'b'), (2, 'c')]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In [6]: import string
In [7]: s = string.ascii_uppercase
In [8]: E = enumerate(s)
In [9]: s
Out[9]: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

In [10]: list(E)
Out[10]:
[(0, 'A'),
(1, 'B'),
此处略...

In [11]: for i in E:
....: print(i, end=' ')
....:
In [12]: E = enumerate(s)
In [13]: for i in E:
print(i, end=' ')
....:
(0, 'A') (1, 'B') (2, 'C') (3, 'D') (4, 'E') (5, 'F') (6, 'G') (7, 'H') (8, 'I') (9, 'J') (10, 'K') (11, 'L') (12, 'M') (13, 'N') (14, 'O') (15, 'P') (16, 'Q') (17, 'R') (18, 'S') (19, 'T') (20, 'U') (21, 'V') (22, 'W') (23, 'X') (24, 'Y') (25, 'Z')

枚举类用法
int 常量默认从1开始,我们来看个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In [16]: from enum import Enum

In [17]: Month = Enum('Month', ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'))
In [19]: print(Month.January)
Month.January

In [20]: print(Month['January'])
Month.January

In [21]: print(Month['January'].value)
1

In [22]: print(Month(4))
Month.April
In [24]: for name, members in Month.__members__.items():
print("%s => %s => %s" % (name, members, members.value))
....:
January => Month.January => 1
February => Month.February => 2
March => Month.March => 3
April => Month.April => 4
May => Month.May => 5
June => Month.June => 6
July => Month.July => 7
August => Month.August => 8
September => Month.September => 9
October => Month.October => 10
November => Month.November => 11
December => Month.December => 12

自定义枚举类(自定义int常量从0开始)
@unique帮助我们检查没有重复值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
In [29]: from enum import Enum, unique

In [30]: @unique
....: class Myday(Enum):
....: Sun = 0
....: Mon = 1
....: Tue = 2
....: Wed = 3
....: Thu = 4
....: Fri = 5
....: Sat = 6
....:

In [31]: Myday.Fri
Out[31]: <Myday.Fri: 5>

In [32]: print(Myday.Fri)
Myday.Fri

In [33]: print(Myday.Fri.value)
5
In [34]: print(Myday['Fri'])
Myday.Fri

In [35]: print(Myday(5))
Myday.Fri

In [37]: for name, members in Myday.__members__.items():
....: print("%s, %s, %s" % (name, members, members.value))
....:
Sun, Myday.Sun, 0
Mon, Myday.Mon, 1
Tue, Myday.Tue, 2
Wed, Myday.Wed, 3
Thu, Myday.Thu, 4
Fri, Myday.Fri, 5
Sat, Myday.Sat, 6

python_01_基础篇下

  • 目录
  • 位运算
  • 程序编码
  • 用户交互

第四节 位运算

1
2
3
4
5
6
位运算:
&与 : 同位都为1则为1
|或 : 同位有1则为1
^异或: 同位相异为1,相同为0
<<n左移位: 左移n位(保留左位),右边补n个0
>>n右移位: 右移n位(去掉右位),左边补n个0

&运算:都为1

1
2
3
4
00110001
01111111
00110001
`

|运算:或为1

1
2
3
00110001
01111111
01111111

^运算:相异为1

1
2
3
11001101
01111111
10110010

<<3左移位:左边110保留

1
2
11010001
11010001000

>>3右移位:右边001不保留

1
2
11010001
00011010

第五节 程序编码

bytes、str 区别

python3 中bytes、str是有区别的

  • bytes/str的区别:bytes 是byte的序列,而str是unicode 序列
  • bytes并不能存储中文,需要先定义成str类型后encode()编码
  • 之间的转换是编码,解码完成。 方式: b1 = str1.encode()/ b1.decode()
  • 网络传输中都是用的bytes类型二进制进行传输(socket编程发送必须bytes类型)
  • b(bytes)只能接收ASCII 的值
  • python3与大多数软件运行在内存中都是unicode编码

b表示方法(bytes)只能接收ASCII的值, 直接传的中文为字符串 unicode编码,一个unicode两个字节,一个汉字两个字节。

1
2
3
4
>>> b1 = b'hello world'   # bytes只能接收ASCII样的值
>>> b2 = b'你好'
File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.

将中文转换为bytes (转为ASCII里面能支持的格式,默认为utf-8)

1
2
3
4
5
6
>>> b2 = '你好'.encode('utf-8')
>>> b3 = bytes('你好', encoding='utf-8')
>>> type(b2)
<class 'bytes'>
>>> b2
b'\xe4\xbd\xa0\xe5\xa5\xbd'

看看下面的转换是否能领悟点什么

1
2
3
4
5
6
7
8
9
10
>>> test_str = '你是最好的!'
>>> test_b = test_str.encode() # 不指定时默认encode()成utf-8
>>> test_b
b'\xe4\xbd\xa0\xe6\x98\xaf\xe6\x9c\x80\xe5\xa5\xbd\xe7\x9a\x84\xef\xbc\x81'
>>> for i in test_b:
... print(i, end=' ')
228 189 160 230 152 175 230 156 128 229 165 189 231 154 132 239 188 129
>>> for i in test_str:
... print(i, end=' ')
你 是 最 好 的 !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@ubuntu:~# cat utf-8.txt 
我是最好的!
root@ubuntu:~# iconv -f utf-8 -t gbk utf-8.txt
ϒˇخºõģ¡
root@ubuntu:~# iconv -f utf-8 -t gbk utf-8.txt > gbk.txt
root@ubuntu:~# cat gbk.txt
ϒˇخºõģ¡
>>> f = open('gbk.txt', 'rb')
>>> test = f.read()
>>> test
b'\xce\xd2\xca\xc7\xd7\xee\xba\xc3\xb5\xc4\xa3\xa1\n'
>>> test.decode('gbk')
'我是最好的!\n'
>>> f.close()

编码总结

编码过程: 任意unicode到bytes的过程
解码过程: bytes到unicode的过程

1
2
3
4
5
6
7
8
9
10
pycharm默认以UTF-8存数据到硬盘(unicode to UTF-8)   一个编码过程
python3默认以UTF-8读数据到内存(UTF-8 to unicode) 一个解码过程
#coding:utf-8 也是指明了用什么编码读数据到内存,一个解码过程

#这里open虽然文件是UTF8存的,此时要以utf8读, utf8 to unicode, 是一个解码过程
with open("test.txt",'r',encoding='utf8') as f:
f.read()

python3字符串就是unicode, 任意unicode只要编码后就是bytes
'你好'.encode('utf8')

第六节 用户交互

for python2.x
name = raw_input(“What is your name:”)
for python3.x
name = input(“What is your name:”)
eg: 想要输入密码时不可见,可以利用getpass模块的getpass()方法

1
2
3
4
5
6
7
8
root@apt:/mnt# cat getp.py 
#!/usr/bin/env python3
import getpass
pwd = getpass.getpass("请输入密码:")
print(pwd)
root@apt:/mnt# python3 getp.py
请输入密码:
123

python_01_基础篇上

  • 目录
  • python简介
  • python变量
  • 数据类型

第一节 简介

Python 简介

Python 安装
More info: 官网

Python第一个程序斐波那契数列

1
2
3
4
5
6
7
8
9
# Python 3: Fibonacci series up to n
>>> def fib(n):
>>> a, b = 0, 1
>>> while a < n:
>>> print(a, end=' ')
>>> a, b = b, a+b
>>> print()
>>> fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Python 注释
单行注释:#
多行注释:英文三引号 ‘’’
‘’’
say somethig
‘’’
有种特殊的用法,此时并非注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@apt:/mnt/proper# cat people_info.py 
#!/usr/bin/env python3
name = input("your name: ").strip()
age = input("your age: ").strip()
salary = input("your money: ").strip()

info = ''' -------- day day up ------------
name: %s
age: %s
salary: %s
''' % (name, age, salary)

print(info)
root@apt:/mnt/proper# python3 people_info.py
your name: wxq
your age: 18
your money: 5000
-------- day day up ------------
name: wxq
age: 18
salary: 5000

Python代码长相

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3                  # (1)程序起始行
"this is a test module" # (2)模块文档(文档字符串)
import os # (3)模块导入
import sys
debug = True # (4)全局变量定义
class FooClass(object): # (5)类定义
"Foo class"
pass
def func(*args, **kwargs): # (6)函数定义
"test function"
foo = FooClass()
if debug:
print("run test()")
if __name__ == '__main__': # (7)主程序
func()

第二节 变量

2.1 变量规范

变量: 字母,数字,下划线且不能以数字开头,并系统己经引用的关键字不能为变量名
关键字
[‘and’, ‘as’, ‘assert’, ‘break’, ‘class’, ‘continue’, ‘def’, ‘del’, ‘elif’, ‘else’, ‘except’, ‘exec’, ‘finally’, ‘for’, ‘from’, ‘global’, ‘if’, ‘import’,
‘in’, ‘is’, ‘lambda’, ‘not’, ‘or’, ‘pass’, ‘print’, ‘raise’, ‘return’, ‘try’, ‘while’, ‘with’, ‘yield’]

1
2
3
4
In [2]: name = "wxq"

In [3]: print(name)
wxq

2.2 变量标准

eg: age_of_name = ‘wxq’ #习惯上

AGE_OF_NAME = "XX"  #常量
Age_Of_Name = "XX"  #驼峰体
Age_of_name = "xx"  #类名

第三节 数据类型

3.1 数字

int(整型)
long(长整型) python3 中己经没有了
float(浮点型)
complex(复数)

3.2 布尔值

True 1
False 0

3.3 字符串

不可变类型
字符串常用功能:
字符串拼接

join()方法: 用于指定字符把序列中的每一个元素连接起来

1
2
3
4
In [11]: str = '_'
In [12]: seq = ('a', 'b', 'c')
In [13]: str.join(seq)
Out[13]: 'a_b_c'

移除前后空白
分割
len()长度
index()索引
split()切片
格式化输出
% 格式化输出
%s 字符串
%d 数字
%f 符点
%r 原生字符串,不会对\n \t进行转换

1
2
3
In [5]: name = 'wxq'
In [6]: print("hello, %s" % name)
hello, wxq

1
2
3
4
# 字符串.center()方法+颜色格式化输出
In [22]: print("\033[32;1m%s\033[0m" % "wxq".center(50, '-'))

-----------------------wxq------------------------

format 格式化输出

1
2
In [7]: "<{tag}>{str}</{tag}>".format(tag='b', str='hello world')
Out[7]: '<b>hello world</b>'

3.4 列表

可变类型
name = [‘hello’, ‘world’]
通过下标访问列表中元素,下标从0开始计数

1
2
3
4
5
In [9]: name[0]
Out[9]: 'hello'

In [10]: name[-1]
Out[10]: 'world'

列表常用操作:
切片:取出多个元素
追加
插入
修改
删除
扩展

3.5 字典

python支持dictionary,采用key-value存储方式,在存放时根据key算出value的存放位置,这样取的时候根据key直接拿到value,这也说明了为什么字典查找速度比列表快的原因。

由于dict根据key来计算value的存储位置,就决定了dict的key必须是不可变对象,利于每次计算相同的key得出的相同的结果,这个通过key计算位置的算法称为哈希算法(Hash)。要保证hash的正确性,作为key的对象就不能变.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In [2]: dict_test = {}
In [3]: for i in range(4):
...: k = 'f%s' % (i+1)
...: v = 'v%s' % i
...: dict_test[k] = v
...:
In [4]: dict_test
Out[4]: {'f1': 'v0', 'f2': 'v1', 'f3': 'v2', 'f4': 'v3'}

In [5]: dict_test.get('f4')
Out[5]: 'v3'

In [6]: for k,v in dict_test.items():
...: print(k,v)
...:
('f1', 'v0')
('f2', 'v1')
('f3', 'v2')
('f4', 'v3')

3.6 元组

3.7 集合

可变集合
集合:一组无序排列的可哈希的值,集合没有特定语法格式,使用工厂函数创建。
支持:
支持集合关系测试:并集
支持成员关系测试:in /not in/迭代
不支持: 索引,元素获取,切片

集合创建

1
2
3
4
5
6
7
8
>>> set1 = set([1,2,3])    # 用set创建
>>> set1
{1, 2, 3}
>>> s1 = {'a', 'b', 'c'} # 或用{}创建
>>> s1
{'b', 'c', 'a'}
>>> type(s1)
<class 'set'>

项目 描述 符号表示
len(s1) 返回s1项的长度 len(s1)
s1.copy 制作s1的副本
s1.difference(s2) 求差集,返回所有在s1中,但不在s2中的项 s1 - s2
s1.intersection(s2) 求交集,返回所有同时在s1 s2中的项 s1 & s2
s1.union(s2) 求并集,返回所有在s1或s2中的项 s1 l s2(竖线)
s1.symmetric_differencee(s2) 求对称差集,返回所有在s1或s2中,但又不同时在s1 s2中的项,即并集减交集 s1 ^ s2
s1.isdisjoin(s2) 如果s1 s2没有相同项,则返回True
s1.issubset(s2) 如果s1是s2的一个子集,则返回True
s1.issuperset(s2) 如果s1是s2的一个父集,则返回True
max(s1) 求最大值 max(s1)
min(s1) 求最小值 min(s1)

3.8 集合forzent()

可变集合