Python散记(学无止境)

  1. Python主要有命令行模式和交互模式
  2. 保存文件不能用Word和Windows自带的记事本。Word保存的不是纯文本文件,而记事本会自作聪明地在文件开始的地方加上几个特殊字符(UTF-8 BOM),结果会导致程序运行出现莫名其妙的错误。
  3. 在头部加上一个特殊的注释 #!/usr/bin/env python3 就可以像运行.exe文件一样运行.py文件了
  4. print()函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出:
>>> print('The quick brown fox', 'jumps over', 'the lazy dog')
The quick brown fox jumps over the lazy dog
print()会依次打印每个字符串,遇到逗号“,”会输出一个空格,因此,输出的字符串是拼起来的。
  1. 缩进的坏处就是“复制-粘贴”功能失效了
  2. 整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差。
  3. 如果字符串里面有很多字符都需要转义,就需要加很多\,为了简化,Python还允许用r’‘表示’'内部的字符串默认不转义,可以自己试试:
>>> print('\\\t\\')
\       \
>>> print(r'\\\t\\')
\\\t\\
  1. 如果字符串内部有很多换行,用\n写在一行里不好阅读,为了简化,Python允许用’’’…’’'的格式表示多行内容,可以自己试试:
>>> print('''line1
... line2
... line3''')				#这个点号是换行的时候它自己加上去的
line1
line2
line3
  1. / 除法的结果永远是浮点数 // 地板除的结果永远是整数
  2. ASCII、Unicode和UTF-8的关系
    Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
    Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。
    ASCII编码是1个字节,而Unicode编码通常是2个字节。
    本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。
    UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
  3. 计算机系统通用的字符编码工作方式:
    在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
    用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件
    浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
  4. 对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符
  5. 由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
    Python对bytes类型的数据用带b前缀的单引号或双引号表示:
    x = b’ABC’
    要注意区分’ABC’和b’ABC’,前者是str,后者虽然内容显示得和前者一样,但bytes的每个字符都只占用一个字节。
  6. 以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:
>>> 'ABC'.encode('ascii')
b'ABC'
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
  File "", line 1, in 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
纯英文的str可以用ASCII编码为bytes,内容是一样的,含有中文的str可以用UTF-8编码为bytes。含有中文的str无法用ASCII编码,因为中文编码的范围超过了ASCII编码的范围,Python会报错。
  1. 如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法:
>>> b'ABC'.decode('ascii')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
如果bytes中包含无法解码的字节,decode()方法会报错:
>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
Traceback (most recent call last):
  ...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
如果bytes中只有一小部分无效的字节,可以传入errors='ignore'忽略错误的字节:
>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
'中'
  1. 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
  1. 格式化字符串:
    如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
  1. 要删除指定位置的元素,用pop(i)方法,其中i是索引位置:
>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']
  1. 如果要定义一个空的tuple,可以写成():
>>> t = ()
>>> t
()
  1. 只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:
>>> t = (1,)
>>> t
(1,)
  1. 要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。
  2. 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断。也就是控制科学吗。
  3. if语句执行有个特点,它是从上往下判断,如果在某个判断上是True,把该判断对应的语句执行后,就忽略掉剩下的elif和else
  4. 循环是让计算机做重复任务的有效的方法。
    break语句可以在循环过程中直接退出循环,而continue语句可以提前结束本轮循环,并直接开始下一轮循环。这两个语句通常都必须配合if语句使用。
    要特别注意,不要滥用break和continue语句。break和continue会造成代码执行逻辑分叉过多,容易出错。大多数循环并不需要用到break和continue语句
  5. Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
  6. dict的key必须是不可变对象
  7. 字典初始化 使用大括号
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
  1. 通过key放入数据 使用索引key
>>> d['Adam'] = 67
>>> d['Adam']
67
  1. 要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:
>>> 'Thomas' in d
False
二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value:
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
  1. set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
  2. 通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
  1. remove(key)方法可以删除元素:
>>> s.remove(4)
>>> s
{1, 2, 3}
  1. 借助抽象,我们才能不关心底层的具体计算过程,而直接在更高的层次上思考问题。
    空函数
    34.如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop():
pass

pass还可以用在其他语句里,比如:

if age >= 18:
    	pass

缺少了pass,代码运行就会有语法错误。

  1. 让我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数,数据类型检查可以用内置函数isinstance()实现:
def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x
  1. 函数的参数
  • 函数的参数有五种包括:必选参数、默认参数、可变参数、关键字参数和命名关键字参数。

  • 位置参数:
    位置参数是必选参数,传入的实参按照顺序分别赋给不同的形参。

  • 默认参数:

作用:
使用默认参数可以简化函数的调用。

注意事项:

  1. 必选参数在前,默认参数在后,否则Python的解释器会报错

  2. 如何设置默认参数?
    在调用函数的时候,传入的参数如果经常变化的话,那么就设置它为必选参数;而如果它每次输入时基本上时一样的,那么我们就设置它为默认参数,这样一来就起到了简化函数调用的作用。

  3. 调用的时候,可以按照顺序传入默认参数,同时也可以以赋值的方式传入。

  4. 如果设置默认参数L是一个变量,它指向对象[],每次调用该函数,就会改变L的内容,在下次调用时,默认参数L的内容就已经变了,不再是函数定义时的[]了。

所以,在定义默认参数要牢记一点:默认参数必须指向不变对象!

我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。

  • 可变参数:
    即传入的参数的个数可变(可以不传入参数)

实例:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
	return sum

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple。,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:

>>> calc(1, 2)
5
>>> calc()
0

Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

>>> nums = [1, 2, 3]
>>> calc(*nums)
14
#*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
  • 关键字参数:
    可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

实例:

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw) 
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

作用:
它可以扩展函数的功能。

实例:

>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

  • 命名关键字参数:
    如果要限制接受的关键字参数的名字,就可以用命名关键字参数,

    实例:
    	def person(name, age, *, city, job):
    	print(name, age, city, job)
    

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。

调用方式如下:

>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

注意:
1.如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需一个特殊分隔符*了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

2.命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "", line 1, in 
TypeError: person() takes 2 positional arguments but 4 were given

3.由于命名关键字参数city具有默认值,调用时,可不传入city参数:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer
  • 参数的组合:

定义参数的顺序是:必选参数,默认参数,可变参数,命名关键字参数和关键字参数。

实例:

def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    	print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

def 3(a, b, c=0, *args, d, **kw):
    	print('a =', a, 'b =', b, 'c =', c, 'args =', args,'d =', d, 'kw =', kw)
    	
  1. Python切片操作
  • 字符串,列表,元组都可以进行切片操作。

神操作:
a = L[:]
简单一步切片就可实现复制功能。

>>> del a
>>> a
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'a' is not defined
>>> c
'223'
#通过简单的实验,我们发现,此并不是简单的贴标签,而是真正在内存中实现了复制。

按照步长取值:
以0.01为步长取0-1的数

			Octave:
					>>t = [0:0.01:1]
			Python:
					>>> L[:1:0.01]
			#实际上,大部分编程语言都是这样按步长取值的
			
  1. 迭代:
  • 只要是可迭代对象,无论有无下标,都可以迭代。

  • 对于字典的迭代:

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d:
...     print(key)
...
a
c
b

说明:
1.字典并没有按照顺序打印,这也说明了字典内部并不是顺序存储,而是用了 哈希算法

2.字典只打印了key但是却没有打印出值来,但不代表不能。
如果要迭代value,可以用for value in d.values();
如果要同时迭代key和value,可以用for k, v in d.items()

  • 可迭代对象:
    如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False
#isinstance()函数可以判断一个实例与一种类型是否匹配,如果是就返回True,否则
返回False;常用于判断数据的类型。

  1. 列表生成式:
  • 作用:
    运用列表生成式,可以快速生成list,可以通过一个list推导出另一个list,而代码却十分简洁。

  • 最简单的用法:
    list(range(1, 11))
    #生成含有1-10的列表

  • 高级用法:
    格式:
    >>> [【要生成的元素】for 【迭代元素】 in【迭代范围】]

    实例:

	1.简单生成
		>>> [x * x for x in range(1, 11)]
		[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
	2.	选择元素生成
		>>> [x * x for x in range(1, 11) if x % 2 == 0]
		[4, 16, 36, 64, 100]
	3.	两层循环
		>>> [m + n for m in 'ABC' for n in 'XYZ']
		['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
	4.	对字典进行操作
		>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
		>>> [k + '=' + v for k, v in d.items()]
		['y=B', 'x=A', 'z=C']
	5.	
		>>> L = ['Hello', 'World', 'IBM', 'Apple']
		>>> [s.lower() for s in L]
		['hello', 'world', 'ibm', 'apple']
  1. 生成器
  • IDEA:
    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。所以,如果列表元素可以在循环的过程中按照某种算法不断推算出后续的元素呢,这样就不必创建完整的list,从而节省大量的空间。

你可能感兴趣的:(Python)