python---基础知识回顾(一)(引用计数,深浅拷贝,列表推导式,lambda表达式,命名空间,函数参数逆收集,内置函数,hasattr...)

一:列表和元组(引用计数了解,深浅拷贝了解)

序列:序列是一种数据结构,对其中的元素按顺序进行了编号(从0开始)。典型的序列包括了列表,字符串,和元组

列表是可变的(可以进行修改),而元组和字符串是不可变得(一旦创建了就是固定的)。

列表操作:

>>> a = [,,]
>>> type(a)
<class 'list'>
>>> id(a) >>> a.append()  //可以修改内容,不会改变其内存地址
>>> a
[, , , ]
>>> id(a)

元组操作:

>>> b = (,,,)
>>> b[]=3  //无法进行修改或者添加
Traceback (most recent call last):
File "<stdin>", line , in <module>
TypeError: 'tuple' object does not support item assignment

字符串(数字和字符串是存放在常量区中):

>>> s = "dasda"
>>> id(s) >>> s[]
'a'
>>> s[]='c'    //无法进行修改(是将字符串数据保存在常量区了)
Traceback (most recent call last):
File "<stdin>", line , in <module>
TypeError: 'str' object does not support item assignment
>>> s = 'fawawfaw'  //这种修改是对其重新赋值,而不是进行修改 注意:此时由于原来的常量字符串没有任何变量指向,引用计数变为0的时候(系统将对该数据进行回收)
>>> id(s)
>>> s = "asdf"
>>> id(s) >>> b = "asdf"    //由于字符串存放在常量区,不可修改,当多个变量的数值都是该常量,那么指向是一致的(同一块内存)
>>> id(b)

补充:

id():类似于C语言中的指针,可以查看其在内存中的编号地址

is:可以查看两个变量是不是一个引用(相同对象)

a =
b =
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) >>> id(b)
14179616
//其实实际上还是放在常量区中同一块区域(只不过这里使用了shell命令行,在不同模块,内存不一致)

使用函数进行规避由于在不同模块导致的内存id不一致:

>>> def printid():
... a = "aaaaa fefagagaw wafwa"
... b = "aaaaa fefagagaw wafwa"
... print(id(a),id(b))
...
>>> printid()
14179472   //相同id,相同对象

对于其他数据类型或者对象,其创建时数据存放在局部变量区,不是同一个对象:

>>> def getid():
... a = [,,]
... b = [,,]
... print(id(a),id(b))
...
>>> getid()
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()

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()

python字符串是如何存储在内存中的

Python的内存管理以及垃圾回收

监控Python中的引用计数

补充:浅拷贝和深拷贝:

浅拷贝:只是指向同一块内存区域,当改变其中一个变量的值(会去修改内存区域中的值<前提是可以修改>),导致另一个变量(相同指向)数据也会改变,像字典(dict),列表(List)等

>>> a = [,]
>>> id(a) >>> b = a
>>> id(b) >>> a
[, ]
>>> b
[, ]
>>> b[]=
>>> a
[, ]
>>> b
[, ]

深拷贝:直接将所有数据进行拷贝到自己的内存空间中去:

>>> from copy import deepcopy
>>> a = [,]
>>> id(a) >>> b = a
>>> id(b) >>> c = deepcopy(a) //或者使用切片也可以实现深拷贝 d = a[:]
>>> id(c) >>> a
[, ]
>>> b
[, ]
>>> c
[, ]

好,回归正题,接着说序列:

通过分片操作可以访问序列的一部分,其中分片需要两个索引号来指出起始和结束。

元组是不可变的,在某些方面相对于列表来说少了灵活性,那么他的意义何在:

.元组可以在映射(和集合的成员中),当做键使用,而列表不行
.元组可以作为好多内建函数和方法的返回值存在(不希望改变)

补充:列表推导式:是利用其它列表创建新列表,类似于for

>>> [x*x for x in range()]
[, , , , , , , , , ] >>> [x*x for x in range() if x % == ]
[, , , ] >>> [(x,y) for x in range() for y in range()]
[(, ), (, ), (, ), (, ), (, ), (, ), (, ), (, )] >>> boys = ['chris','aragn','bona','baer']
>>> gilrs = ['alice','banane','clarce']
>>> [b+'+'+g for b in boys for g in girls if b[] == g[]]
['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
\\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

执行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'])

sys.modules.keys()

执行keys可以查看引入的模块

>>> 'socket' in sys.modules.keys()
False
>>> import socket
>>> 'socket' in sys.modules.keys()
True

上面可以看出在引入模块后,全局字典会发生变化。是在全局字典中添加了引入模块的缓存

,我们可以通过这个全局字典进行调用操作

>>> a = [,]
>>> b = sys.modules['copy'].deepcopy(a)
>>> id(a) >>> id(b)

二:exec和eval(命名空间概念)

1.exec:执行一个字符串的语句

>>> a =
>>> 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() //
scope['sqrt'] //
作用域:变量存储在作用域(也叫作命名空间)中。python有两类主要的作用域---全局作用域globals()['param']和局部作用域locals()['param']。作用域可以嵌套
调用全局变量
x =
def change_global():
global x
x = x + print(x) #
嵌套作用域:
def foo():
def bar():
print("hello")
return bar

注意:在全局不能访问局部变量,但是在局部可以访问到全局变量,并且可以修改(需要使用global,像上面)

>>> x =
>>> def change_global():
... x = 11    #不使用global的话,进行“修改”,只是单纯的声明了一个局部变量,修改也无法改变到全局变量
... print(x)
...
>>> change_global() >>> x

如果局部没有找到所需的变量,就会往外进行查找,没有找到就会报错。

2.eval:是用于求值,而不是像exec那样执行语句

>>> eval("a=1")  #语句执行,会出错
Traceback (most recent call last):
File "<stdin>", line , in <module>
File "<string>", line
a=
^
SyntaxError: invalid syntax
>>> eval("6+7")    #求值的话是可以的

上面两个的使用不多。

二:函数

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",,,,[,,],{"k1":v1"}) aa (, , , [, ], {'k1': 'v1'})

**返回字典

>>> def coll(name,**param):
... print(name,param) #param是元组类型,默认是空元组
coll("asd",x1=,x2=)
//asd {'x2': , 'x1': }

联合使用:

>>> def coll(name,*args,**kwargs):
... print(name,args,kwargs) #param是元组类型,默认是空元组 >>> coll("asd",,,,[,,],x1=,x2=)
asd (, , , [, ]) {'x2': , 'x1': }

重点:参数收集的逆过程:(不是收集,是分配)

>>> def add(x,y):
... return x+y
...
>>> params = (,)
>>> res = add(*params) #是将数据分配给函数
>>> res
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':} with_stars(**args)
without_stars(args)
#两者都可以实现,达到同样的效果,所以星号只在定义函数(允许使用不定数目的参数)或者调用分割字典或序列时有用
#daf is 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()):
... print(item)
...

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

>>> def cond(x):
... return x% == >>> for item in filter(cond,range()):
... print(item)
...

reduce() 函数会对参数序列中元素进行累积。

函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

>>> from functools import reduce
>>> ret = reduce(add,range())
>>> ret

注意在3版本以上大部分内置函数需要从functools中进行引入

这些内置函数,部分也可以使用列表推导式,来实现:

map:

>>> [x*x for x in range()]
[, , , , ]

filter:

>>> [x for x in range() if x % ==]
[, , , ]

补充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())

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)
上一篇:yiic创建YII应用 "php.exe"不是内部或外部命令 解决办法


下一篇:【RabbitMQ】三种类型交换器 Fanout,Direct,Topic(转)