zoukankan      html  css  js  c++  java
  • Python学习日记(十)—— 杂货铺(全局变量补充、Python参数传递、字符串格式化、迭代器、生成器)

    全局变量补充

    python自己添加了些全局变量

    print(vars())
    """
    结果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00795650>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/Sullivan/PycharmProjects/q1/day12/global.py', '__cached__': None} """

    这些全局变量的作用

    #__doc__ 包含py文件的注释,文件的注释在——文件内容的最上面用三引号引起来
    print(__doc__)
    
    #__file__ 包含当前文件的路径
    print(__file__)
    
    #__package__ 对于单读文件的package是没有意义的,代表当前的py文件在哪几个文件夹下
    print(__package__)#当前文件没有,会返回None
    from day2 import homework
    print(homework.__package__) #文件夹套文件夹时用点"."区分
    #结果:day2
    
    #__cached__ 缓存,对于py文件是可以设置一个缓存的,python2里没有,了解即可
    print(__cached__)#当前文件也有,会返回None
    from day2 import homework
    print(homework.__cached__)
    #结果:C:UsersSullivanPycharmProjectsq1day2\__pycache__homework.cpython-36.pyc
    
    #__name__ 如果当前执行的是当前文件,它的__name__就是__main__,其它的不管是导入还是其它的操作__name__就是文件名
    print(__name__)
    #结果__main__
    from day2 import homework
    print(homework.__name__)
    #结果:day2.homework
    
    #__builtins__ 里边放的就是内置函数
    
    #__loader__和__spec__ 都是p3中新加的
    
    # 因为程序的入口文件就是用户当前执行的文件,所以以后写主程序文件的时候
    if __name__ == "__main__":
        execute()
        #防止其他文件导入该文件时,执行主函数
    name的实际应用
    #利用sys,os模块和__file__变量,把路径添加到system path中
    
    import os,sys
    p1 = os.path.dirname(__file__)    #获取当前路径
    p2 = "bin"
    my_dir = os.path.join(p1,p2)    #字符串拼接,拼接出新路径
    
    sys.path.append(my_dir)    #添加到system path里面
    file的实际应用

    Python参数传递

     Python参数传递 有引用传递&值传递两种

    值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。

    a1 = 520
    a2 = a1
    print(a1,a2)
    结果:520 520
    a2 = a1 + 1
    print(a1,a2)
    结果:520 521
    

    引用传递:也称地址传递,在方法调用时,实际上是把参数的引用(传的是地址,而不是参数的值)传递给方法中对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。

    a1 = [1,2]
    a2 = a1
    a2.append(3)
    print(a1)
    结果:[1, 2, 3]
    print(a2)
    结果:[1, 2, 3]  

    Python中,数字、字符或者元组等不可变对象类型都属于值传递,而字典dict或者列表list等可变对象类型属于引用传递

    如果要想修改新赋值后原对象不变,则需要用到python的copy模块,即对象拷贝。对象拷贝又包含浅拷贝和深拷贝。下面用例子来说明

    例一

    import copy
    l1 = [[1, 2], 3]
    
    l2 = copy.copy(l1)
    l2.append(4)      #因为浅拷贝之拷贝第一层,所以对第一层操作不会影响l1
    l2[0].append(5)   #因为浅拷贝只拷贝的第一层,所以对第二层的操作还是值传递,所以l1和l2中都有列表的第一个元素都会添加一个5
    print(l1)
    print(l2)
    结果:
    [[1, 2, 5], 3]
    [[1, 2, 5], 3, 4]

    例二

    l1 = [[1, 2], 3]
    l3 = copy.deepcopy(l1)
    
    l3[0].append(6)
    print(l1)
    print(l3)    #深拷贝全部拷贝,所以只是l3的值变了,l1并没有改变
    # 结果:
    [[1, 2], 3]
    [[1, 2, 6], 3]  

    从上例可以看出,copy.copy属于浅拷贝,拷贝的是第一层list,而copy.deepcopy属于深拷贝,对list所有子元素都进行深拷贝。  

    字符串格式化

    Python的字符串格式化有两种方式: 百分号方式、format方式

    百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存。

    1、百分号方式

    %[(name)][flags][width].[precision]typecode
    • (name)      可选,用于选择指定的key
    • flags          可选,可供选择的值有:
      • +       右对齐;正数前加正好,负数前加负号;只有这个会在输出后给整数加上正号(+)
      • -        左对齐;正数前无符号,负数前加负号;
      • 空格    右对齐;正数前加空格,负数前加负号;
      • 0        右对齐;正数前无符号,负数前加负号;用0填充空白处
    • width         可选,占有宽度
    • .precision   可选,小数点后保留的位数
    • typecode    必选
      • s,获取传入对象的__str__方法的返回值,并将其格式化到指定位置
      • r,获取传入对象的__repr__方法的返回值,并将其格式化到指定位置
      • c,整数:将数字转换成其unicode对应的值,10进制范围为 0 <= i <= 1114111(py27则只支持0-255);字符:将字符添加到指定位置
      • o,将整数转换成 八  进制表示,并将其格式化到指定位置
      • x,将整数转换成十六进制表示,并将其格式化到指定位置
      • d,将整数、浮点数转换成 十 进制表示,并将其格式化到指定位置
      • e,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(小写e)
      • E,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(大写E)
      • f, 将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
      • F,同上
      • g,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是e;)
      • G,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是E;)
      • %,当字符串中存在格式化标志时,需要用 %%表示一个百分号

    注:Python中百分号格式化是不存在自动将整数转换成二进制表示的方式

    功能示例:

    # %[(name)][flags][width].[precision]typecode
    
    s = ["i am %s,age %d" % ('ciri',18)]
    # (name)
    s = "i am %(n1)s,age %(n2)d" % {"n1":"ciri","n2":16}
    s = "i am %(n1)s,age %(n1)s" % {"n1":"ciri"}    #也可以两个共用一个值
    
    #flags和width一般放到一起用,一般用不到
    #字符
    s = "i am %(n1)+10s ellie" % {"n1":"ciri"}
    s = "i am %(n1)-10s ellie" % {"n1":"ciri"}
    s = "i am %(n1) 10s ellie" % {"n1":"ciri"}
    s = "i am %(n1)010s ellie" % {"n1":"ciri"}
    #数字
    s = "age %(n2)+10d ellie" % {"n2":16}
    s = "age %(n2)+10d ellie" % {"n2":-16}
    
    s = "age %(n2)-10d ellie" % {"n2":16}
    s = "age %(n2)-10d ellie" % {"n2":-16}
    
    s = "age %(n2) 10d ellie" % {"n2":16}
    s = "age %(n2) 10d ellie" % {"n2":-16}
    
    s = "age %(n2)010d ellie" % {"n2":16}
    s = "age %(n2)010d ellie" % {"n2":-16}
    
    #precision——默认输出6位小数
    s = "age %f ellie" % 1.2
    s = "age %.2f ellie" % 1.2      #指定小数保留几位

    常用格式化:

    tpl = "i am %s" % "alex"
     
    tpl = "i am %s age %d" % ("alex", 18)
     
    tpl = "i am %(name)s age %(age)d" % {"name": "alex", "age": 18}
     
    tpl = "percent %.2f" % 99.97623
     
    tpl = "i am %(pp).2f" % {"pp": 123.425556, }
     
    tpl = "i am %.2f %%" % {"pp": 123.425556, }

    2、Format方式

    [[fill]align][sign][#][0][width][,][.precision][type]
    都是中括号[],所以参数都可以省略
    • fill           【可选】空白处填充的字符
    • align        【可选】对齐方式(需配合width使用)
      • <,内容左对齐
      • >,内容右对齐(默认)
      • =,内容右对齐,将符号放置在填充字符的左侧,且只对数字类型有效。 即使:符号+填充物+数字
      • ^,内容居中
    • sign         【可选】有无符号数字
      • +,正号加正,负号加负;
      •  -,正号不变,负号加负;
      • 空格 ,正号空格,负号加负;
    • #            【可选】对于二进制、八进制、十六进制,如果加上#,会显示 0b/0o/0x,否则不显示
    • ,            【可选】为数字添加分隔符,如:1,000,000
    • width       【可选】格式化位所占宽度
    • .precision 【可选】小数位保留精度
    • type         【可选】格式化类型
      • 传入” 字符串类型 “的参数
        • s,格式化字符串类型数据
        • 空白,未指定类型,则默认是None,同s
      • 传入“ 整数类型 ”的参数
        • b,将10进制整数自动转换成2进制表示然后格式化
        • c,将10进制整数自动转换为其对应的unicode字符
        • d,十进制整数
        • o,将10进制整数自动转换成8进制表示然后格式化;
        • x,将10进制整数自动转换成16进制表示然后格式化(小写x)
        • X,将10进制整数自动转换成16进制表示然后格式化(大写X)
      • 传入“ 浮点型或小数类型 ”的参数
        • e, 转换为科学计数法(小写e)表示,然后格式化;
        • E, 转换为科学计数法(大写E)表示,然后格式化;
        • f , 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
        • F, 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
        • g, 自动在e和f中切换
        • G, 自动在E和F中切换
        • %,显示百分比(默认显示小数点后6位)

     常用格式化:

    # [[fill]align][sign][#][0][width][,][.precision][type]
    
    tpl = "i am {}, age {}".format("seven", 18)
    tpl = "i am {}, age {}".format(*["seven", 18,'ciri'])  #传入列表,列表的元素可以比前面的内容所
    #可以传索引
    tpl = "i am {0}, age {1}".format("seven", 18)
    tpl = "i am {0}, age {1}".format(*["seven", 18])
    #通过name获取
    tpl = "i am {name}, age {age}".format(name="seven", age=18)
    tpl = "i am {name}, age {age}".format(**{"name": "seven", "age": 18})#传字典要穿加上**
    #第一个0表示拿第几个元素
    tpl = "i am {0[0]}, age {0[1]}".format([1, 2, 3], [11, 22, 33])
    #分别接收字符串、数字和浮点数
    tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1)
    tpl = "i am {:s}, age {:d}".format(*["seven", 18])
    
    tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18)
    tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18})
    
    tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
    tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15)
    tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)

    生成器——generator

    列表生成器

    # 先到 for x in range(10) 取元素,再把取出来的元素按照 前面的内容(x,x+1,x*2) 进行操作,然后把结果依次放到列表中
    
    a = [x for x in range(10)] print(a) a = [x+1 for x in range(10)] print(a) a = [x*2 for x in range(10)] print(a) 结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10

    赋值一种方法 

    t = ('ciri',8)
    a,b = t    #值和变量的个数要相同,否则会报错
    
    print(a)
    print(b)
    结果:
    ciri
    8

    如何创建生成器?

    方法一:小括号的方式

    #把列表生成式的中括号,改成小括号,就变成了一个生成器
    s = (x for x in range(10))
    print(s)
    
    # <generator object <genexpr> at 0x03726360>
    #输出的是一个生成器对象,所有的值压根就没有被创建出来(重点)
    之前的列表生成式生成了10个值,就相当于10盘菜,已经做出来了,想什么时候成就什么时候吃,想什么时候调动就什么时候调用,想吃第几道就吃第几道。
    生成器就相当于,厨师脑子里的10道菜,想吃的时候才做出来,你不吃就不会做出来,只能按顺序吃(0,1...8,9),不能隔着吃,也不能倒着吃

    方法二:yield方式

    def func():
        print('ok')
        yield 1
        print('ok2')
        yield 2
    
    print(func)     # <function func at 0x03163540> 可以看出func还是一个函数
    
    func()  #不会执行函数,此时func()是一个生成器对象
    
    print(func())
    # <generator object func at 0x034764B0> 可以看出 func加上括号() 是一个生成器对象
    

    yield的执行过程

    def func():
        print('ok')
        yield 1
        print('ok2')
        yield 2
    
    next(func())
    next(func())
    结果:
    ok
    ok2
    
    
    for i in func():
        print(i)
    结果:
    ok    
    1    
    ok2   
    2
    

    如何使用生成器中的对象?

    s = (x for x in range(10))
    print(s)
    
    # 方法一:
    print(s.__next__())#内部特殊的方法,不建议用
    
    # 方法二:
    #python3中新加的方法
    print(next(s))  #以后就用这种方法
    
    # 方法三:
    #python2中可以直接调用next方法
    print(s.next)
    
    # 方法四:
    for i in s:
        print(i)
    
    #for就是内部调用next方法

    斐波那契数列

    def fib(max):
        n,b,a = 0,0,1
        while n<max:
            print(b)    #最开始的值
            yield b
            b, a = a, b + a     #会先把b+a计算出来
            n = n + 1
    
    
    g = fib(8)
    next(g)
    next(g)
    next(g)
    next(g)
    b, a = a, b + a为什么这个可以,把a的值赋值给b,b+a的值赋值给a
    
    b = a
    a = b + a  这个不行
    
    #因为b, a = a, b + a会先计算出来b+a的值
    补充:b, a = a, b + a为什么这个可以

     send方法

    send和next的区别就是,send可以给yield前面的变量传值

    def bar():
        print('ok')
        count = yield 1
        print(count)        #第二次进来,就会直接把send的值,直接传给yield前的参数count
        yield 2
    
    b = bar()
    
    #b.send('ciri') 会报错,因为第一次进来,执行到到yield就冻结了,出去了,所以第一次不知道给谁赋值,所以就不能用send传参数
    
    ret1 = b.send(None)    #用send第一次进入时,只能这么写,等价于next(b)
    print(ret1)  #结果  1
    
    ret2 = b.send('ciri')
    print(ret2)  #结果:2
    

    实例:用yield实现伪并发

    #做和吃是同时发生的
    import time
    
    def consumer(name):
        print("%s 准备吃包子啦!" % name)
        while True:
            baozi = yield
    
            print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
    
    def producer(name):
        c = consumer('A')
        c2 = consumer('B')
        next(c)
        next(c2)
        print("老子开始准备做包子了")
        for i in range(10):
            time.sleep(1)
            print("做了2个包子")
            c.send(i)
            c2.send(i)
    producer("ciri")

    迭代器——iterator  

    生成器都是迭代器,迭代器不一定是生成器 

    如何创建一个迭代器?

    #iter方法就做一件事情,返回了一个迭代器对象
    
    li = [1,2,3,4]
    d = iter(li)
    print(d)
    # <list_iterator object at 0x034A4770>   iterator迭代器,iterable可迭代对象
    

    什么是迭代器?
      满足两个条件:1.有iter方法  2.有next方法

    for循环后面加的是什么?
      可迭代对象

    什么是可迭代对象?
      现象上——能进行 for循环的,都是可迭代对象
      本质上——内部有iter方法的,就是可迭代对象

    执行迭代器

    li = [1,2,3,4]
    
    d = iter(li)    #iter方法就做了一件事情,返回了一个迭代器对象
    
    print(next(d))
    print(next(d))
    

    补充:for循环 执行时的内部操作三件事

    1.  调用可迭代对象的iter方法,返回一个迭代器对象
    2.  调用迭代器的next方法
    3.  处理stopiteration异常

    实例:操作文件

    f = open('abc.txt','r')
    for i in f.readlines():     #假如文件很大的话,会全部都放到内存中去
        pass
    for i in f():       #这里的f就是一个可迭代对象,节省内存空间
        pass
    

    练习:使用文件读取,找出文件中最长的行

    max(len(x.strip()) for x in open('/hello/abc','r'))
    

       

    Python的字符串格式化有两种方式: 百分号方式、format方式

    百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存。

  • 相关阅读:
    hdu4276 依赖背包
    poj1155 依赖背包
    cf219d 基础换根法
    贪婪大陆——(树状数组)
    数星星(树状数组或者线段树)
    拓扑排序基础题——排序
    Codeforces Round #511 (Div. 1) T2 Little C Loves 3 II
    除虫药水(简单dp)
    烽火传递(单调队列优化dp,然而蒟蒻用一个优先队列做)
    ZOJ----3471Most powerful(简单状压dp)
  • 原文地址:https://www.cnblogs.com/houzhaohui/p/7455352.html
Copyright © 2011-2022 走看看