原文发布于个人博客(好望角),并在博客持续修改更新,此处可能更新不及时。
抽空复习了一下python的语言特性,其中容易忘记、混淆的点特地记录如下。
输入输出
基本数据类型
编码问题
dic & list
set
相当于dic 的 key ,同样不可放入重复的元素。这里的集合不可改变针对的是不可变元素,如果集合内有可变元素列表是可以改变的。
t1=(1,2,3,[1,2,3])
t1[-1][-1]=4
t1
>>> (1, 2, 3, [1, 2, 4])
不可变元素
占位符
返回值
检查参数
函数参数类型
程序设计能设计成不变对象(例如:str,None等扽那个)是最好的。因为不易导致修改数据带来的错误。而且在多任务的环境下不用加锁,因为数据是不会改变的。
递归函数
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
>>> import os # 导入os模块,模块的概念后面讲到
>>> [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
# 杨辉三角的迭代生成
# 停止条件和输出格式在调用的时候定义,最大限度地提高函数的重用率
# 列表元素还可以直接加?
def triangles():
l = [1]
while 1:
yield l
l = [1] + [l[n] + l[n + 1] for n in range(len(l) - 1)] + [1]
# 斐波那契数列的迭代生成
# 不需要中间变量的变量赋值方法,节省一点内存
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
Func | 语法 | 作用 | retype |
---|---|---|---|
hasattr | hasattr(object, name) | 判断 对象中是否含有 该属性。 | True / False |
setattr | setattr(object, name, values) | 给对象的属性 赋值,若属性不存在,先创建再赋值。 | None |
getattr | getattr(object, name[,default]) | 获取 属性数值。 | 属性存在时,返回 属性数值;否则根据 默认输出值 返回 或 报 AttributeError。 |
delattr | delattr(object, name) | 删除属性。 | 属性存在则无返回,否则报 AttributeError。 |
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
# 例子一
>>> a=b=['hello','world'];a.append('hello')
>>> print(b)
['hello','world','hello']
# 例子二
>>> a=b='hello';a='world'
>>> print(b)
hello
对于可变类型来说,两个变量名指向相同的内存地址的时候相当于给同一个内存地址起了两个名字。如果改变一个变量名的内容,并不会开辟新的内存,而是直接改变原来内存地址中的内容。也就是说对于不可变类型,不同的变量名指向的内存地址永远是相同的。
对于不可变类型来说,两个变量指向相同的内容时拥有共同的内存地址(id(arg) 命令可以查看),但是改变一个变量之后相当于另外开辟一块新内存,其内存 id 会随之改变。
但是起名可变和不可变的原因呢?是相对于函数传参来说的。
def test(a_int, b_list):
a_int = a_int + 1
b_list.append('13')
print('inner a_int:' + str(a_int))
print('inner b_list:' + str(b_list))
if __name__ == '__main__':
a_int = 5
b_list = [10, 11]
test(a_int, b_list)
print('outer a_int:' + str(a_int))
print('outer b_list:' + str(b_list))
>>> inner a_int:6
>>> inner b_list:[10, 11, '13']
>>> outer a_int:5
>>> outer b_list:[10, 11, '13']
所谓的可变类型,就是传入函数中,函数中的变化会同步到函数外的变量。类似引用传递(可以把引用理解为一个箭头,这个箭头指向某块内存地址,而引用传递,传递过来的就是这个箭头,当你修改内容的时候,就是修改这个箭头所指向的内存地址中的内容,因为外部也是指向这个内存中的内容的,所以,在函数内部修改就会影响函数外部的内容。)
而不可变类型,传入函数中的操作会事先新创造一个内存地址,所以并不会影响函数外的变量值。类似值传递(表示传递直接传递变量的值,把传递过来的变量的值复制到形参中,这样在函数内部的操作不会影响到外部的变量)。
a = [1,2,3,[1,2]]
b = a
b[-1] = [1,2,3]
print(a,b)
>>> [[1,2,3,[1,2,3]],[1,2,3,[1,2,3]]]
l1=[1,2,3,[1,2,3]]
l2=l1.copy()
l2[-1].append(4) # 子对象仍相同,同步变化
l2.append(5) # 父对象不同,不会同步变化
print(l1,l2)
>>> [[1,2,3,[1,2,3,4]], [1,2,3,[1,2,3,4],5]]
import copy
l1=[1,2,3,[1,2,3]]
l2=copy.deepcopy(l1)
l2[-1].append(4)
print(l1)
>>> [1,2,3,[1,2,3]]
# 深度拷贝是将原对象中所有的值完全复制一份存放在内存中(包括可变数据类型对象)。这样遇到原对象即使是更改,也不会影响其值。
# 复制引用与copy.copy, copy.deepcopy
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )
>>> ('a = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5])
>>> ('b = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5])
>>> ('c = ', [1, 2, 3, 4, ['a', 'b', 'c']])
>>> ('d = ', [1, 2, 3, 4, ['a', 'b']])
运算符 | 描述 |
---|---|
** | 指数 (最高优先级) |
~ + - | 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) |
* / % // | 乘,除,取模和取整除 |
+ - | 加法减法 |
>> << | 右移,左移运算符 |
& | 位 ‘AND’ |
^ | | 位运算符 |
<= < > >= | 比较运算符 |
<> == != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
is is not | 身份运算符 |
in not in | 成员运算符 |
not or and | 逻辑运算符 |
print(100 - 25 * 3 % 4)
>>> 97
read([size])
文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止,整个文件返回为一个字符串对象,文件很大时候readline()
每次读出一行内容,所以,读取时占用内存小,比较适合大文件,但是速度慢啊!(内存不够时采用)每次读取返回一个字符串对象。reandlines()
读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存。linecache
输出某个文件的第n行, 使用示例如下:text = lincache.getline('a.txt' , 2)
print(text)
s = raw_input('请输入:')
print('你刚才输入了:'+s)
请输入:hhhh
你刚才输入了:hhhh
a = {'s':1 , 'w':1}
b = {'w':1 , 'e':1}
z = {**a , **b}
str.ljust(50,'@')
用 @ 将字符串填充为长度 50 ,@填补在字符串的后面。>>> a = '456123'
>>> a[-3,-1] = 'aaa'
TypeError: 'str' object does not support item assignment
创建新字典的方法
>>> print({}.fromkeys((1,2,8),(3,4)))
{1: (3, 4), 2: (3, 4), 8: (3, 4)}
从本质上讲,自带pop() 、append() 函数的列表结构是以 stack 为基础的。
a = ['a','b','c']
del a[0] #指定删除0位的元素
print(a)
---
> ['b', 'c']
a = ['a','b','c']
a.remove('b') #删除第一个匹配的指定元素,直接改变原数组,无返回值。
print(a)
---
> ['a', 'c']
a = ['a','b','c']
b = ['d','e','f']
# pop的命令,其有返回值,可赋值带出
c = a.pop() #默认删除-1位置元素'c',并将删除元素返回值赋值
d = b.pop(0) #删除0位元素'd',并将删除元素返回值赋值
print(a,b,c,d)
---
> ['a', 'b'] ['e', 'f'] c d
# 错误用法
[5,6].append(9)
list().append(9)
# 正确用法
a = [5,6]
a.append(9)
shuffle()
函数,返回值类型都为None,它们直接作用在原本的列表上,不会创建新对象。import random
L = [2,3,4,56,78,9,0]
random.shuffle(L)
print(L)
当 python 中表示复数的时候,复数之间不能比较大小。
python 中表示复数,实部可以是整数、也可以是浮点数; 而虚部是关于X轴的反转程度。
python 静态类变量可以被实例或者类本身访问并且修改。
heapq 是python自带的完全二叉树结构的类型,常用于堆排序(最小堆,不受初始数据顺序影响)
deque 是python中的双端队列结构
检查函数类型时候只写函数名,不加括号;调用函数时侯加括号,返回函数的运行结果值。
python 是弱语言类型, 不用对变量类型进行直接赋值。但如果调用一个未赋值对象会报 NameError 错误。
Python变量访问时有个LEGB原则,也就是说,变量访问时搜索顺序为Local ==> Enclosing ==> Global ==> Builtin,其实很多语言都遵循这个规则。简单地说,访问变量时,先在当前作用域找,如果找到了就使用,如果没找到就继续到外层作用域看看有没有,找到了就使用,如果还是没找到就继续到更外层作用域找,如果已经到了最外层作用域了还是实在找不到就看看是不是内置对象,如果也不是,抛出异常。
自定义类中,如果我们想要返回特定信息。需要改变函数中的 __ str __ 方法
Stackless并非以库的形式和Python整合,Stackless提供的并发建模工具,比目前其它大多数传统编程语言所提供的工具都更加易用: 不仅用于Python自身,也包括Java、C++,以及其它语言。
Scrapy是Python进行网络抓取的第三方库,包含Scrapy引擎,下载器,爬虫,调度器,Item Pipeline以及中间件,并没有沟通隧道(connect)。
os.listdir(dirname):列出dirname下的目录和文件
os.getcwd():获得当前工作目录
os.curdir:返回当前目录(’.’)
os.chdir(dirname):改变工作目录到dirname
os.path.isdir(name):判断name是不是一个目录,name不是目录就返回false
os.path.isfile(name):判断name是不是一个文件,不存在name也返回false
os.path.exists(name):判断是否存在文件或目录name
os.path.getsize(name):获得文件大小,如果name是目录返回0
os.path.abspath(name):获得绝对路径
os.path.normpath(path):规范path字符串形式
os.path.split(name):分割文件名与目录(事实上,如果你完全使用目录,它也会将最后一个目录作为文件名而分离,同时它不会判断文件或目录是否存在)
os.path.splitext():分离文件名与扩展名
os.path.join(path,name):连接目录与文件名或目录
os.path.basename(path):返回文件名
os.path.dirname(path):返回文件路径
原文发布于个人博客(好望角),并在博客持续修改更新,此处可能更新不及时。