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

执行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 = [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)
原文地址:https://www.cnblogs.com/ssyfj/p/8858382.html