• 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)
  • 相关阅读:
    20172311-ASL测试 2018-1938872补充博客
    20172311《程序设计与数据结构》第四周学习总结
    20172311 实验一《程序设计与数据结构》线性结构 实验报告
    20172311《程序设计与数据结构》第三周学习总结
    20172311《程序设计与数据结构》第二周学习总结
    20172311《程序设计与数据结构》第一周学习总结
    20172311 《程序设计与数据结构》(上)课程总结
    20172311 2017-2018-2 《程序设计与数据结构》实验五报告
    20172311 2017-2018-2 《程序设计与数据结构》第十一周学习总结
    20172323 2018-2019-1 《程序设计与数据结构》课堂作业报告
  • 原文地址:https://www.cnblogs.com/ssyfj/p/8858382.html
Copyright © 2020-2023  润新知