人生苦短,我用Python02:Python程序的基石

时间:June 14, 2017 分类:

目录:

Python的一砖一瓦

基本数据类型

数字 int,long,float,complex(复数) 字符串 str 布尔值 bool 列表 list 元组 tuple 字典 dict

判断数据类型

[root@why ~]# vi test.py
a = 10
print (type(a))
[root@why ~]# python test.py 
<type 'int'>

变量

首先,变量不需要声明,可以包含数字,字母,下划线,不能以数字开头,变量名不能为python内部关键字。

原因就是:

因为程序判定时候需要来确认你输入的是什么,是数字,变量,关键字等等,如果是数字开头的就能直接判断为数字了,规定不让数字为开头,程序分析代码效率会高一些,具体可以参考编译原理

编译原理中的词法分析问题,程序语言的分析分词法和语法两部分。词法分析主要用的是正规文法,即三型文法,主要采用正则表达式分析。正则文法分析器的特点是不回溯(编译器在解析程序时,读到单词的第一个字符就能知道当前这个单词属于哪一类,如果是数字,则可以直接跳入数字处理的模块,若是字符则按变量名来处理)。

如果一个变量以数字开头,那么分析器就必须在遇到第一个或第二个英文字符的时候回溯来确定是否是数字、变量名还是词法错误,这时候就变成了二型文法。二型文法分析器的好处是支持回溯和递归语法(所以语法分析是靠它的),缺点是状态机相比正则文法状态大大增加,而且代码写起来更困难。

考虑到词法分析部分只是用来断字,我们实在是没有为了支持变量名以数字开头这么一个小功能而让整个词法分析部分用二型文法写。最后大家都默认了变量要避免用数字开头。

对于数字,字符串

变量指向内存中的数据,例如a = 1,就会在内存中有一个变量a值为1,而如果把变量赋值给另一个变量,则两个变量指向相同的内存数据

>>> a = 1
>>> b = a
>>> print(id(a))
16126776

16126776为10进制的内存地址

>>> print(hex(id(a)))
0xf61338

0xf61338为16进制的内存地址

>>> print(id(b))
16126776

可以看到a和b内存地址一样

如果给a赋一个新的值

>>> a = 2
>>> print(id(a))
16126752
>>> print(id(b))
16126776

可以看到b依然指向原来的内存地址

另外,对于Python对于在-5~257的区间,使用相同的内存地址

对于列表

不过这些不适用于列表等

>>> c = [1,2,3]
>>> d = c
>>> print(id(c))
140348430105272
>>> print(id(d))
140348430105272
>>> c[0]=4
>>> print(id(c))
140348430105272
>>> print(id(d))
140348430105272

流程判断

if  <条件1>:
    <代码>
elif <条件2>:
    <代码>
elif <条件3>:
    <代码>
else:
    <代码>

循环

for循环

for 元素 in 序列: 
    statement

while循环

while <条件>:
    <代码>

循环跳出

  • continue 在循环的某一次执行中,如果遇到continue, 那么跳过这一次操作,进行下一次的操作
  • break 停止执行整个循环

运算符

算数运算符

>>>print 1+9        # 加法
>>>print 1.3-4      # 减法
>>>print 3*5        # 乘法
>>>print 4.5/1.5    # 除法
>>>print 3**2       # 乘方     
>>>print 10%3       # 求余数
>>>print 10//3

对于除,python2和python3有些区别

python2中需要引入模块

[root@why practice_code]# python
Python 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-17)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 9 / 2
>>> print(a)
4
>>> from __future__ import division
>>> print(a)
4
>>> a = 9 / 2
>>> print(a)
4.5

而python3却不需要

(env35) [root@why ~]# python
Python 3.5.0 (default, Jun  4 2017, 02:43:17) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-18)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 9 / 2
>>> print(a)
4.5

比较运算符

==, !=, >, >=, <, <=

赋值运算符

start += 1  

逻辑运算符

and
or
not

成员运算符

in
not in 

身份运算符

is 
is not

运算符的详细信息可以参考 http://www.runoob.com/python/python-operators.html

运算符优先级

Python各数据类型

类的方法

n1 = 123 n2 = 456 print(n1 + n2) print(n1.__add__(n2))

数字

创建一个数字,】注意不要写为a = '123'

>>> a = 123
>>> print a
123

这里默认就调用了int

>>> b = int(123)
>>> print b
123

实质上是调用了int.__init__()来进行创建,然后在内存中创建,将内存地址返回给变量b

在代码中是这么定义的 def __init__(self,x,base=10):

>>> c = int('0b100',2)
>>> print c
4
  • 对于32位系统,整型的范围为-231~231-1
  • 对于64位系统,整型的范围为-263~263-1

如果超过这一长度,就会自动转换为长整型long类型,但是python对长整形没有定义长度,也就是理论上有多大内存就能占用多大。

字符串操作

获取字符串长度

>>> s = 'why'
>>> print(len(s))
3

一般可以用在while循环,举个例子

s = [1,2,3,4,5,6,7]
start 0
while start < len(s)
    temp = s[start]
    print(temp)
    start += 1

字符串分片和索引

>>> print(s[0:2])
wh
>>> print(s[0])
w

字符串首字母大写(capitalize)

>>> a = 'why is op'
>>> print a.capitalize()
Why is op
  • isalnum字母数字
  • isalpha字母
  • isdigit数字
  • islower小写
  • istitle标题
  • isupper判断是否为大写
  • swapcase大写变小写,小写变大写

字符串补全(center)

>>> a = 'why'
>>> print a.center(10)
   why    
SyntaxError: invalid syntax
>>> print a.center(10,'_')
___why____

这个是居中补全,也有ljust和rjust的左右补全

>>> a = 'why'
>>> print a.ljust(1,'a')
why
>>> print a.ljust(20,'a')
whyaaaaaaaaaaaaaaaaa
>>> print a.rjust(20,'a')
aaaaaaaaaaaaaaaaawhy

判断字符串中是否包含

>>> print a.count('w')
1
>>> print a.count('a')
0
>>> print a.count('w',3)
0

判断字符串结尾(endswith)

>>> print a.endswith('y')
True
>>> print a.endswith('h')
False

开头用startswith

可以指定字符串范围

>>> print a.endswith('h',0,2)
True

将tab转化为8个空格(expandtabs)

>>> a = 'why\top'
>>> print a.expandtabs()
why     op
>>> print a.expandtabs(20)
why                 op

判断字符串中是否包含某些字符串(find)

>>> a = 'why is why'
>>> print a.find('why')
0
>>> print a.find('wanghongyu')
-1

rfind方法是从右往左找,而index找不到报错

字符串格式化输出

>>> a = 'name is {0},age is {1}'
>>> print a
name is {0},age is {1}
>>> print a.format('why',24)
name is why,age is 24

当然我更倾向

>>> name = 'why'
>>> age = 24
>>> print('name is %s,age is %d'%(name,age))
name is why,age is 24
  • %s 字符串(采用str()的显示)
  • %r 字符串(采用repr()的显示)
  • %c 单个字符
  • %b 二进制整数
  • %d 十进制整数
  • %i 十进制整数
  • %o 八进制整数
  • %x 十六进制整数
  • %e 指数(基底写为e)
  • %E 指数(基底写为E)
  • %f 浮点数
  • %F 浮点数,与上相同
  • %g 指数(e)或浮点数(根据显示长度)
  • %G 指数(E)或浮点数(根据显示长度)
  • %% 字符"%"

还有就是

name = 'why'
age = 24
str = 'name is %(name)s,age is %(age)d'% locals()

或者

str = 'name is %(b1)s,age is %(n2)d'% {'n1':'why', 'n2':'24'}

当然相同内容可以是两个n1。

更多的可以参考Python开发【第五篇】:Python基础之杂货铺

将可迭代的列表等进行拼接

>>> a = ['why','is','op']
>>> print '_'.join(a)
why_is_op

去除空格(strip)

>>> a = ' why '
>>> print a.lstrip()
why 
>>> print a.rstrip()
 why
>>> print a.strip()
why

把字符串分割为元组中的三个元素(partition)

>>> a = 'why is op'
>>> print a.partition(' ')
('why', ' ', 'is op')
>>> print a.partition('is')
('why ', 'is', ' op')

这样做会把分隔符左侧,分隔符,分隔符右侧变为三个元素

通过分隔符分割字符串

>>> a = 'why is op'
>>> print a.split()
['why', 'is', 'op']
>>> a = 'why_is_op'
>>> print a.split('_')
['why', 'is', 'op']

字符串转换为标题格式(Title)

>>> a = 'why is op'
>>> print a.title()
Why Is Op

字符串替换

>>> a = 'why is why'
>>> print a.replace('why','wanghongyu',1)
wanghongyu is why
>>> print a.replace('why','wanghongyu')
wanghongyu is wanghongyu

关于迭代中文字符串

对于python3和python2支持不同

python2

>>> name = '王宏宇'
>>> for i in name:
...     print(i)
... 




®


®

输出为乱码

python3

>>> name = '王宏宇'
>>> for i in name:
...     print(i)
... 
王
宏
宇
>>> for i in name:
...     print(bytes(i,encoding='utf-8'))
... 
b'\xe7\x8e\x8b'
b'\xe5\xae\x8f'
b'\xe5\xae\x87'

字符串和bytes类型转换

>>> b = bytes(name,encoding='utf-8')
>>> print(b)   
b'\xe7\x8e\x8b\xe5\xae\x8f\xe5\xae\x87'
>>> s = str(b,encoding='utf-8')
>>> print(s)          
王宏宇

列表和元组

定义列表

>>> name = ['mabiao','why','pqt']

列表索引

>>> name[0]
'mabiao'

列表分片

>>> name[0:2]
['mabiao', 'why']

列表长度

>>> len(name)
3

列表倒叙

>>> a = [1, 2, 3, 4, 5]
>>> a.reverse()
>>> a
[5, 4, 3, 2, 1]

列表添加元素(append)

>>> name.append('yanwei')
>>> print name
['mabiao', 'why', 'pqt', 'yanwei']

统计列表元素在列表中的个数(count)

>>> name.append('yanwei')
>>> name.append('yanwei')
>>> print name
['mabiao', 'why', 'pqt', 'yanwei', 'yanwei', 'yanwei']
>>> name.count('yanwei')
3

合并列表(entend)

>>> name.extend(['chenyu','liuyiping','lihongsheng'])
>>> print(name)
['mabiao', 'why', 'pqt', 'yanwei', 'yanwei', 'yanwei', 'chenyu', 'liuyiping', 'lihongsheng']

输出元素索引(index)

>>> name.index('why')
1

在列表指定位置插入元素(insert)

>>> name.insert(1,'wanghongyu')
>>> print(name)
['mabiao', 'wanghongyu', 'why', 'pqt', 'yanwei', 'yanwei', 'yanwei', 'chenyu', 'liuyiping', 'lihongsheng']

取出列表元素并赋值(pop)

>>> a = name.pop()
>>> print(a)
lihongsheng
>>> print(name)
['mabiao', 'wanghongyu', 'why', 'pqt', 'yanwei', 'yanwei', 'yanwei', 'chenyu', 'liuyiping']

列表中移除元素(remove)

>>> name.remove('yanwei')
>>> print(name)
['mabiao', 'wanghongyu', 'why', 'pqt', 'yanwei', 'yanwei', 'chenyu', 'liuyiping']

当然也可以通过del删除

>>> del name[0]
>>> print(name)
['liuyiping', 'mabiao', 'pqt', 'wanghongyu', 'why', 'yanwei', 'yanwei']
>>> del name[0:2]
>>> print(name)
['pqt', 'wanghongyu', 'why', 'yanwei', 'yanwei']

列表倒序(reverse)

>>> name.reverse()
>>> print(name)
['liuyiping', 'chenyu', 'yanwei', 'yanwei', 'pqt', 'why', 'wanghongyu', 'mabiao']

列表排序(sort)

>>> name.sort()
>>> print(name)
['chenyu', 'liuyiping', 'mabiao', 'pqt', 'wanghongyu', 'why', 'yanwei', 'yanwei']

元组和列表的操作基本是一致的,但是元组是无法进行修改的,也就是说增,删,改都不可以,也就是说只支持,索引,len,切片,count,index,通过for循环迭代,如果希望创建一个不会被修改的可以使用元组。

不过元组的元素不能被修改,但是元组中的元素的元素可以被修改。

举个栗子:

>>> a = (1,{'k':'v'})
>>> a[1]['k']='value'
>>> print a
(1, {'k': 'value'})

原因就是字符串如果一旦进行操作就是产生一个新的数据,而字典,列表是直接对自身的内部的操作。

字典

定义字典

>>> why = {'name':'wanghongyu','age':24,'job':'op'}

字典索引

>>> print(why['name'])
wanghongyu

迭代打印字典的key

>>> for i in why:
...     print(i)
... 
job
age
name

输出字典的key

>>> print(why.keys())
['job', 'age', 'name']

输出字典的value

>>> print(why.values())
['op', 24, 'wanghongyu']

输出字典成员

>>> print(why.items())
[('job', 'op'), ('age', 24), ('name', 'wanghongyu')]
>>> for k,v in why.items():
...     print(k)
...     print(v)
... 
job
op
age
24
name
wanghongyu

清空字典

>>> why.clear()
>>> print(why)
{}

获取字典元素

与直接指定key方法类似,不过get可以指定默认值

>>> why = {'name':'wanghongyu','age':24,'job':'op'}
>>> why.get('age')
24
>>> why.get('ages')
>>> why.get('ages',24)
24

判断key是否存在

>>> why.has_key('age')
True
>>> why.pop('age')
24

取出字典的元素并赋值

>>> why.popitem()
('job', 'op')
>>> print(why)
{'name': 'wanghongyu','age':24}

添加字典元素

>>> a = {1:2,3:4}
>>> a.update({5:6})
>>> print a
{1: 2, 3: 4, 5: 6}
>>> a[7] = 8
>>> print a
{1: 2, 3: 4, 5: 6, 7: 8}

删除字典元素

>>> del why['job']
>>> print(why)
{'age': 24, 'name': 'wanghongyu'}

取出字典元素

>>> why2={'age':24,'job':'op'}
>>> why.update(why2)
>>> print(why)
{'job': 'op', 'age': 24, 'name': 'wanghongyu'}

字典的fromkeys

>>> a = dict.fromkeys(['k1','k2','k3'],[])
>>> print a
{'k3': [], 'k2': [], 'k1': []}
>>> a['k1'].append('why')
>>> print a
{'k3': ['why'], 'k2': ['why'], 'k1': ['why']}

可以看到在一个列表添加why,会对所有的列表添加why,也就是说这三个value指向同一个

>>> b = {'k3': [], 'k2': [], 'k1': []}
>>> b['k1'].append('why')
>>> print b
{'k3': [], 'k2': [], 'k1': ['why']}

而我直接创建的就是只有k1有值,也可以通过下面方法实现fromkeys

>>> li = []
>>> c = {'k3': li, 'k2': li, 'k1': li}
>>> c['k1'].append('why')
>>> print c
{'k3': ['why'], 'k2': ['why'], 'k1': ['why']}

集合

创建集合

>>> s = set()
>>> s.add(1)
>>> print s
set([1])
>>> s.add(1)
>>> print s
set([1])
>>> s.add(2)
>>> print s
set([1, 2])

列表等转换为集合

>>> l = [1,2,3,1]
>>> s = set(l)
>>> print s
set([1, 2, 3])

清空集合

>>> s.clear()
>>> print s
set([])

移除集合元素

>>> s = {1,2,3}
>>> s.discard(3)
>>> print s
set([1, 2])
>>> s.discard(3)
>>> print s
set([1, 2])


>>> s.remove(2)
>>> print s
set([1])
>>> s.remove(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 2

discard和remove的不同在于remove一个不存在的元素的时候会报错

取交集

>>> s1 = {1,2,3}
>>> s2 = {2,4}
>>> s1.intersection(s2)
set([2])
>>> print s1
set([1, 2, 3])
>>> s1.intersection_update(s2)
>>> print s1
set([2])

isdisjoint()是否有交集,有交集输出True,没有输出False issuperset()是否为其父集 issubset()是否为其子集

取并集

>>> s1 = {1,2,3}
>>> s2 = {2,4}
>>> s1.difference(s2)
set([1, 3])
>>> s2.difference(s1)
set([4])
>>> s1.difference_update(s2)
>>> print s1
set([1, 3])

pop()移除并赋值给变量 union()取并级 symmetric_difference()创建两个集合的差集的集合 symmetric_difference_update()创建两个集合的差集的集合并替换 update()循环添加到集合中

以上复杂了

  • a & b 交集
  • a - b 差集
  • a | b 合集

集合使用

将一个新字典中的添加到旧字典中,如果key重复则覆盖,key不存在则新增

old_dic={
    '#1':11,
    '#2':22,
    '#3':33,
}
new_dic={
    '#1':12,
    '#3':33,
    '#5':55
}

old_keys = old_dic.keys()
new_keys = new_dic.keys()

old_sets = set(old_keys)
new_sets = set(new_keys)

del_sets = old_sets.difference(new_sets)
add_sets = new_sets.difference(old_sets)
update_sets = old_sets.intersection(new_sets)

print(old_sets)
print(new_sets)
print(del_sets)
print(add_sets)
print(update_sets)

执行结果

{'#2', '#1', '#3'}
{'#1', '#5', '#3'}
{'#2'}
{'#5'}
{'#1', '#3'}

然后可以根据这些来进行for循环进行操作

字符串以颜色输出

print("\033[31;1m你好麽,\033[0m我很好。。")
print("\033[32;1m你好麽,\033[0m我很好。。")
print("\033[33;1m你好麽,\033[0m我很好。。")
print("\033[34;1m你好麽,\033[0m我很好。。")
print("\033[35;1m你好麽,\033[0m我很好。。")
print("\033[36;1m你好麽,\033[0m我很好。。")
print("\033[37;1m你好麽,\033[0m我很好。。")


print("\033[41;1m你好麽,\033[0m我很好。。")
print("\033[42;1m你好麽,\033[0m我很好。。")
print("\033[43;1m你好麽,\033[0m我很好。。")
print("\033[44;1m你好麽,\033[0m我很好。。")
print("\033[45;1m你好麽,\033[0m我很好。。")
print("\033[46;1m你好麽,\033[0m我很好。。")
print("\033[47;1m你好麽,\033[0m我很好。。")

返回结果

最后说一句

在python中,如果写入一个字符串,字符串通过C的方式写入,字符串写入后占据固定的长度的连续内存地址,如果修改字符串,是无法直接修改内存的字符,就会直接创建一个新的字符串,写入到内存地址。

而对于列表等可进行修改的,是通过C的链表方式进行写入,每个元素会有一个指向下一个内存地址的指针,不是使用连续的内存地址,也就可以进行扩展,每个元素其实是索引和值。浅拷贝和深拷贝的结果一样

当然,拷贝也分深拷贝和浅拷贝,分别是copy.copy()和copy.deepcopy(),对于字符串浅拷贝就是两个对象指向同一内存地址,对于列表,元组,元素,字典或者他们的嵌套,我们浅拷贝的时候,只是重新拷贝出一份索引在内存中,进而赋值给对象,其内部的元素都是指向了相同的内存地址,而深拷贝,不论多少层嵌套,都会拷贝到新的内存地址空间。可以通过id()来进行查看。