python---基础知识回顾(一)(引用计数,深浅拷贝,列表推导式,lambda表达式,命名空间,函数参数逆收集,内置函数,hasattr...)
一:列表和元组(引用计数了解,深浅拷贝了解)
序列:序列是一种数据结构,对其中的元素按顺序进行了编号(从0开始)。典型的序列包括了列表,字符串,和元组
列表是可变的(可以进行修改),而元组和字符串是不可变得(一旦创建了就是固定的)。
列表操作:
>>> a = [1,2,3] >>> type(a) <class 'list'> >>> id(a) 14182600 >>> a.append(4) //可以修改内容,不会改变其内存地址 >>> a [1, 2, 3, 4] >>> id(a) 14182600
元组操作:
>>> b = (1,2,3,) >>> b[1]=3 //无法进行修改或者添加 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
字符串(数字和字符串是存放在常量区中):
>>> s = "dasda" >>> id(s) 14187408 >>> s[1] 'a' >>> s[1]='c' //无法进行修改(是将字符串数据保存在常量区了) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment >>> s = 'fawawfaw' //这种修改是对其重新赋值,而不是进行修改 注意:此时由于原来的常量字符串没有任何变量指向,引用计数变为0的时候(系统将对该数据进行回收) >>> id(s) 14191664
>>> s = "asdf" >>> id(s) 14185784 >>> b = "asdf" //由于字符串存放在常量区,不可修改,当多个变量的数值都是该常量,那么指向是一致的(同一块内存) >>> id(b) 14185784
补充:
id():类似于C语言中的指针,可以查看其在内存中的编号地址
is:可以查看两个变量是不是一个引用(相同对象)
a = 1 b = 1 print(a is b) #true a = "aaaa" b = "aaaa" print(a is b) #true
注意:
不同的程序块中(在IDLE,python shell中 每一行就算是一个单独程序块)即使相同字符串也是单独创建对象。
而对于上面在shell中属于的相同字符串(或者数字)中之所以是相同的,是因为整数和短小的字符串,Python在内存都会缓存这些对象,以便继续使用,所以我们获取时会发现这些相同变量是一致的id
同样用shell命令行来执行较长的字符串,那么则不会是同一个id,是因为较长的字符串是不会进行缓存
主要原因还是因为shell命令行中每一行都是一个单独的程序块,所以即便是相同字符串都可能不是一个对象
所以推荐测试时,不要使用shell命令行,也可以使用函数,进行规避 >>> a = "aaaaa fefagagaw wafwa" >>> b = "aaaaa fefagagaw wafwa" >>> a is b False >>> id(a) 14179544 >>> id(b) 14179616
//其实实际上还是放在常量区中同一块区域(只不过这里使用了shell命令行,在不同模块,内存不一致)
使用函数进行规避由于在不同模块导致的内存id不一致:
>>> def printid(): ... a = "aaaaa fefagagaw wafwa" ... b = "aaaaa fefagagaw wafwa" ... print(id(a),id(b)) ... >>> printid() 14179472 14179472 //相同id,相同对象
对于其他数据类型或者对象,其创建时数据存放在局部变量区,不是同一个对象:
>>> def getid(): ... a = [1,2,] ... b = [1,2,] ... print(id(a),id(b)) ... >>> getid() 14182536 14183624 //列表,元组,字典等都不在同一内存块
sys模块中getrefcount():来查看某个对象的引用计数
实际上我们进行查看其引用计数时,需要将数据作为参数传递给getrefcount()函数,所以参数临时创建了一个引用,会导致我们的应用计数相比预期的多一:
>>> def getCount(): ... from sys import getrefcount ... c1 = getrefcount("aaaaaaavvvvvvv") //字符串出现时,本身计数为1,参数又产生一个新的引用计数 返回2 ... 此时执行完引用函数,临时参数消失,引用计数变为1
... a = "aaaaaaavvvvvvv" //变量引用计数又加一 2 ... c2 = getrefcount(a) //作为传参引用计数再次加一 3 ... print(c1,c2) //输出2,3 ... >>> getCount() 2 3
del:会移除一个对象的引用,也会移除这个变量名本身:
>>> def getCount(): ... from sys import getrefcount ... c1 = getrefcount("aaaaaad") ... a = "aaaaaad" ... c2 =getrefcount(a) ... del a //a变量不存在,print(a) NameError: name 'a' is not defined ... c3 = getrefcount("aaaaaad") ... print(c1,c2,c3) ... >>> getCount() 2 3 2
python字符串是如何存储在内存中的
Python的内存管理以及垃圾回收
监控Python中的引用计数
补充:浅拷贝和深拷贝:
浅拷贝:只是指向同一块内存区域,当改变其中一个变量的值(会去修改内存区域中的值<前提是可以修改>),导致另一个变量(相同指向)数据也会改变,像字典(dict),列表(List)等
>>> a = [1,2] >>> id(a) 14182600 >>> b = a >>> id(b) 14182600 >>> a [1, 2] >>> b [1, 2] >>> b[1]=3 >>> a [1, 3] >>> b [1, 3]
深拷贝:直接将所有数据进行拷贝到自己的内存空间中去:
>>> from copy import deepcopy >>> a = [1,2] >>> id(a) 14604168 >>> b = a >>> id(b) 14604168 >>> c = deepcopy(a) //或者使用切片也可以实现深拷贝 d = a[:] >>> id(c) 14182600 >>> a [1, 2] >>> b [1, 2] >>> c [1, 2]
好,回归正题,接着说序列:
通过分片操作可以访问序列的一部分,其中分片需要两个索引号来指出起始和结束。
元组是不可变的,在某些方面相对于列表来说少了灵活性,那么他的意义何在:
1.元组可以在映射(和集合的成员中),当做键使用,而列表不行 2.元组可以作为好多内建函数和方法的返回值存在(不希望改变)
补充:列表推导式:是利用其它列表创建新列表,类似于for
>>> [x*x for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> [x*x for x in range(10) if x % 3 == 0] [0, 9, 36, 81] >>> [(x,y) for x in range(4) for y in range(2)] [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)] >>> boys = ['chris','aragn','bona','baer'] >>> gilrs = ['alice','banane','clarce'] >>> [b+'+'+g for b in boys for g in girls if b[0] == g[0]] ['chris+clarce', 'aragn+alice', 'bona+banane', 'baer+banane']
补充:全局字典(sys.modules模块)
sys.modules是一个全局字典,该字典是python启动后就会加载在内存中的。每当引入新的模块,sys.modules都会记录这些模块。(会起到相当于缓存的作用),第一次引入模块时,sys.modules全局字典会记录该模块。第二次在导入时会直接去字典中查找,加快了程序的运行速度。(操作方法同字典)
>>> sys.modules {'_io': <module 'io' (built-in)>, 'genericpath': <module 'genericpath' from 'C:\ \Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\genericp ath.py'>, 'itertools': <module 'itertools' (built-in)>, 'ntpath': <module 'ntpat h' from 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\l ib\\ntpath.py'>, 'copy': <module 'copy' from 'C:\\Users\\Administrator\\AppData\ \Local\\Programs\\Python\\Python35\\lib\\copy.py'>, 'io': <module 'io' from 'C:\ \Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\io.py'>, 'collections.abc': <module 'collections.abc' from 'C:\\Users\\Administrator\\Ap pData\\Local\\Programs\\Python\\Python35\\lib\\collections\\abc.py'>, '_signal': <module '_signal' (built-in)>, 'sys': <module 'sys' (built-in)>, '__main__': <m odule '__main__' (built-in)>, '_functools': <module '_functools' (built-in)>, 'f unctools': <module 'functools' from 'C:\\Users\\Administrator\\AppData\\Local\\P rograms\\Python\\Python35\\lib\\functools.py'>, '_warnings': <module '_warnings' (built-in)>, '_codecs': <module '_codecs' (built-in)>, '_stat': <module '_stat' (built-in)>, 'os': <module 'os' from 'C:\\Users\\Administrator\\AppData\\Local\ \Programs\\Python\\Python35\\lib\\os.py'>, 'marshal': <module 'marshal' (built-i n)>, 'encodings.latin_1': <module 'encodings.latin_1' from 'C:\\Users\\Administr ator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\encodings\\latin_1.py'>, 'encodings.aliases': <module 'encodings.aliases' from 'C:\\Users\\Administrator\ \AppData\\Local\\Programs\\Python\\Python35\\lib\\encodings\\aliases.py'>, 'oper ator': <module 'operator' from 'C:\\Users\\Administrator\\AppData\\Local\\Progra ms\\Python\\Python35\\lib\\operator.py'>, 'encodings.utf_8': <module 'encodings. utf_8' from 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python3 5\\lib\\encodings\\utf_8.py'>, '_weakref': <module '_weakref' (built-in)>, '_loc ale': <module '_locale' (built-in)>, '_frozen_importlib': <module '_frozen_impor tlib' (frozen)>, 'codecs': <module 'codecs' from 'C:\\Users\\Administrator\\AppD ata\\Local\\Programs\\Python\\Python35\\lib\\codecs.py'>, 'winreg': <module 'win reg' (built-in)>, '_imp': <module '_imp' (built-in)>, 'types': <module 'types' f rom 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\ types.py'>, 'collections': <module 'collections' from 'C:\\Users\\Administrator\ \AppData\\Local\\Programs\\Python\\Python35\\lib\\collections\\__init__.py'>, '_ heapq': <module '_heapq' (built-in)>, 'stat': <module 'stat' from 'C:\\Users\\Ad ministrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\stat.py'>, 'builti ns': <module 'builtins' (built-in)>, '_multibytecodec': <module '_multibytecodec ' (built-in)>, 'heapq': <module 'heapq' from 'C:\\Users\\Administrator\\AppData\ \Local\\Programs\\Python\\Python35\\lib\\heapq.py'>, 'zipimport': <module 'zipim port' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_exte rnal' (frozen)>, '_collections': <module '_collections' (built-in)>, 'nt': <modu le 'nt' (built-in)>, '_operator': <module '_operator' (built-in)>, 'atexit': <mo dule 'atexit' (built-in)>, 'sysconfig': <module 'sysconfig' from 'C:\\Users\\Adm inistrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\sysconfig.py'>, 'en codings': <module 'encodings' from 'C:\\Users\\Administrator\\AppData\\Local\\Pr ograms\\Python\\Python35\\lib\\encodings\\__init__.py'>, '_thread': <module '_th read' (built-in)>, 'errno': <module 'errno' (built-in)>, 'copyreg': <module 'cop yreg' from 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35 \\lib\\copyreg.py'>, '_collections_abc': <module '_collections_abc' from 'C:\\Us ers\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\_collection s_abc.py'>, 'reprlib': <module 'reprlib' from 'C:\\Users\\Administrator\\AppData \\Local\\Programs\\Python\\Python35\\lib\\reprlib.py'>, '_sitebuiltins': <module '_sitebuiltins' from 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Pytho n\\Python35\\lib\\_sitebuiltins.py'>, 'os.path': <module 'ntpath' from 'C:\\User s\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\ntpath.py'>, 'abc': <module 'abc' from 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\P ython\\Python35\\lib\\abc.py'>, '_weakrefset': <module '_weakrefset' from 'C:\\U sers\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\_weakrefse t.py'>, 'encodings.mbcs': <module 'encodings.mbcs' from 'C:\\Users\\Administrato r\\AppData\\Local\\Programs\\Python\\Python35\\lib\\encodings\\mbcs.py'>, '_code cs_cn': <module '_codecs_cn' (built-in)>, 'site': <module 'site' from 'C:\\Users \\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\site.py'>, 'ke yword': <module 'keyword' from 'C:\\Users\\Administrator\\AppData\\Local\\Progra ms\\Python\\Python35\\lib\\keyword.py'>, '_bootlocale': <module '_bootlocale' fr om 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\_ bootlocale.py'>, 'encodings.gbk': <module 'encodings.gbk' from 'C:\\Users\\Admin istrator\\AppData\\Local\\Programs\\Python\\Python35\\lib\\encodings\\gbk.py'>, 'weakref': <module 'weakref' from 'C:\\Users\\Administrator\\AppData\\Local\\Pro grams\\Python\\Python35\\lib\\weakref.py'>}
执行sys.modules会发现是一个字典,内部存放了各个已经导入的模块,例如:
'weakref': <module 'weakref' from 'C:\\Users\\Administrator\\AppData\\Local\\Pro grams\\Python\\Python35\\lib\\weakref.py'>
>>> sys.modules.keys() dict_keys(['_io', 'genericpath', 'itertools', 'ntpath', 'copy', 'io', 'collectio ns.abc', '_signal', 'sys', '__main__', '_functools', 'functools', '_warnings', ' _codecs', '_stat', 'os', 'marshal', 'encodings.latin_1', 'encodings.aliases', 'o perator', 'encodings.utf_8', '_weakref', '_locale', '_frozen_importlib', 'codecs ', 'winreg', '_imp', 'types', 'collections', '_heapq', 'stat', 'builtins', '_mul tibytecodec', 'heapq', 'zipimport', '_frozen_importlib_external', '_collections' , 'nt', '_operator', 'atexit', 'sysconfig', 'encodings', '_thread', 'errno', 'co pyreg', '_collections_abc', 'reprlib', '_sitebuiltins', 'os.path', 'abc', '_weak refset', 'encodings.mbcs', '_codecs_cn', 'site', 'keyword', '_bootlocale', 'enco dings.gbk', 'weakref'])
执行keys可以查看引入的模块
>>> 'socket' in sys.modules.keys() False >>> import socket >>> 'socket' in sys.modules.keys() True
上面可以看出在引入模块后,全局字典会发生变化。是在全局字典中添加了引入模块的缓存
,我们可以通过这个全局字典进行调用操作
>>> a = [1,2] >>> b = sys.modules['copy'].deepcopy(a) >>> id(a) 17435016 >>> id(b) 17434440
二:exec和eval(命名空间概念)
1.exec:执行一个字符串的语句
>>> a = 100 >>> exec("a = a + 10") >>> a 110
>>> from math import sqrt
>>> exec("sqrt = 1")
>>> sqrt(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
像上面这样使用简单形式的exec语句是不正确的,可能会修改到全局数据,影响对代码的执行。是很严重的潜在安全漏洞
正确的方法是:为他提供命名空间-可以放置变量的地方:
from math import sqrt scope = {} exec('sqrt = 1', scope) //将执行放在局部作用域中,不会去干扰到全局作用域python3.5中
#exec "sqrt = 1' in scope //python2.7 sqrt(4) //2 scope['sqrt'] //1
作用域:变量存储在作用域(也叫作命名空间)中。python有两类主要的作用域---全局作用域globals()['param']和局部作用域locals()['param']。作用域可以嵌套
调用全局变量
x = 1 def change_global(): global x x = x + 1 print(x) #2
嵌套作用域: def foo(): def bar(): print("hello") return bar
注意:在全局不能访问局部变量,但是在局部可以访问到全局变量,并且可以修改(需要使用global,像上面)
>>> x = 10 >>> def change_global(): ... x = 11 #不使用global的话,进行“修改”,只是单纯的声明了一个局部变量,修改也无法改变到全局变量 ... print(x) ... >>> change_global() 11 >>> x 10
如果局部没有找到所需的变量,就会往外进行查找,没有找到就会报错。
2.eval:是用于求值,而不是像exec那样执行语句
>>> eval("a=1") #语句执行,会出错 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 a=1 ^ SyntaxError: invalid syntax >>> eval("6+7") #求值的话是可以的 13
上面两个的使用不多。
二:函数
1.参数:参数是存储在局部作用域中,修改参数,默认是不会修改到原数据的(字符串,元组,数字这些无法被修改,只能被覆盖的)
>>> def change(name): ... name="fafwa" ... >>> xm = "xiaoming" >>> change(xm) >>> xm 'xiaoming'
但是当传入一个列表(等可变的数据类型)时,则会修改
>>> def change(name): ... name.append("asd") ... >>> name = ["fea","gef"] >>> change(name) >>> name ['fea', 'gef', 'asd']
可以查看上面的列表操作:当两个变量同时引用一个列表时,他们的确是在引用同一个列表。(默认浅拷贝)
若是想不允许修改原来数据,可以使用切片等方法
>>> change(name[:])
如果想修改参数(不可变的):可以使函数进行返回,覆盖原来值
>>> def change(name): ... name="fafwa" ... return name ... >>> xm = "xiaoming" >>> xm = change(xm) >>> xm 'fafwa'
2.参数收集:
*收集其余数据到元组中
>>> def coll(name,*param): ... print(name,param) #param是元组类型,默认是空元组 coll("asd",1,2,3,[12,34,],{"k1":v1"}) aa (1, 2, 3, [11, 22], {'k1': 'v1'})
**返回字典
>>> def coll(name,**param): ... print(name,param) #param是元组类型,默认是空元组 coll("asd",x1=1,x2=2) //asd {'x2': 2, 'x1': 1}
联合使用:
>>> def coll(name,*args,**kwargs): ... print(name,args,kwargs) #param是元组类型,默认是空元组 >>> coll("asd",1,2,3,[12,34,],x1=1,x2=2) asd (1, 2, 3, [12, 34]) {'x2': 2, 'x1': 1}
重点:参数收集的逆过程:(不是收集,是分配)
>>> def add(x,y): ... return x+y ... >>> params = (1,2) >>> res = add(*params) #是将数据分配给函数 >>> res 3
def with_stars(**kwds): print(kwds['name'],'is',kwds['age'],'years old') def without_stars(kwds): print(kwds['name'],'is',kwds['age'],'years old') args = {'name':"daf",'age':12} with_stars(**args) without_stars(args)
#两者都可以实现,达到同样的效果,所以星号只在定义函数(允许使用不定数目的参数)或者调用分割字典或序列时有用 #daf is 12 years old
3.python内置函数:map,filter,reduce,apply
apply(func[,args[,kwargs]]):调用函数,可以提供参数(3以上已废弃,不讨论)
map(func[,seq[,seq,...]):映射,对序列中的每个元素应用函数 2.7返回列表,3.5返回迭代器
>>> def add(x): ... return x*x ... >>> for item in map(add,range(5)): ... print(item) ... 0 1 4 9 16
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
>>> def cond(x): ... return x%3 == 0 >>> for item in filter(cond,range(10)): ... print(item) ... 0 3 6 9
reduce() 函数会对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
>>> from functools import reduce >>> ret = reduce(add,range(10)) >>> ret 45
注意在3版本以上大部分内置函数需要从functools中进行引入
这些内置函数,部分也可以使用列表推导式,来实现:
map:
>>> [x*x for x in range(5)] [0, 1, 4, 9, 16]
filter:
>>> [x for x in range(10) if x %3 ==0] [0, 3, 6, 9]
补充lambda表达式:用于创建短小的函数
lambda 参数: 返回值:
lambda x,y: return x+y #返回x+y的和
func = lambda x,y: return x+y 赋值给函数
func() 执行函数
reduce(lambda x, y: x+y, range(10))
4.函数其他补充:
函数名是一段内存地址,根据函数名去找到该内存块,按照其中代码进行执行
(1).函数名可以作为值:
def say_ha():
print("hahaha")
def say_gun():
print("gun")
def say_god():
print("god")
func_dict = {'ha':say_ha,'gun':say_gun,'god':say_god}
if __name__ == "__main__":
recv = input("请输入操作").strip() #strip可以去除左右两边字符,默认为空
if recv in func_dict:
func_dict[recv]() #会去执行函数
补充:一般在模块,或者对象中,我使用hasattr(),getattr(),setattr()进行反射查询和调用
hasattr(obj,name)判断一个对象里面是否有name属性或者name方法
>>> class test():
... def run(self):
... print("hahhaha")
...
>>> t = test()
>>> hasattr(t,"run")
True
getattr(obj,name):获取对象object的属性或者方法
>>> class test():
... def run(self):
... print("hahhaha")
...
>>> t = test()
>>> hasattr(t,"run")
True
>>> func = getattr(t,"run") #也可以获取成员变量
>>> func()
hahhaha
setattr(object, name, values):给对象的属性赋值,若属性不存在,先创建再赋值。一般hasattr和getattr联合使用
(2).函数名作为返回值,进行调用(闭包)
def func():
def inner():
return 666
return inner
s = func()
print(s())
(3).函数名可以作为参数:
def index():
print("hahah")
def outer(index):
s = index
s()
outer(index)