• Day4-python基础之函数


    本次学习内容:

    • 字典查询快的原因
    • 字符编码
    • 函数定义
    • 局部变量、全局变量
    • 返回值
    • 嵌套函数
    • 递归(二分查找)
    • 三元运算
    • map
    • lamba
    • 函数式编程
    • 高阶函数
    • 内置函数

    字典查询快的原因

    字典占用内存比列表多,但是查询速度比列表快的多

    为什么会查询速度会快呢?因为他是hash类型的,那什么是hash呢?

    哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法

    dict会把所有的key变成hash 表,然后将这个表进行排序,这样,你通过data[key]去查data字典中一个key的时候,python会先把这个key hash成一个数字,然后拿这个数字到hash表中看没有这个数字, 如果有,拿到这个key在hash表中的索引,拿到这个索引去与此key对应的value的内存地址那取值就可以了。

    那为什么会快呢?通过数字去hash表中查看数字时,采用某种算法,maybe是二分法,查询的次数很少。

    key -->hash值-->类似二分查找,找到hash值索引-->value对应的内存地址

    字符编码

    先说python2

    1. py2里默认编码是ascii
    2. 文件开头那个编码声明是告诉解释这个代码的程序 以什么编码格式 把这段代码读入到内存,因为到了内存里,这段代码其实是以bytes二进制格式存的,不过即使是2进制流,也可以按不同的编码格式转成2进制流,你懂么?
    3. 如果在文件头声明了#_*_coding:utf-8*_,就可以写中文了, 不声明的话,python在处理这段代码时按ascii,显然会出错, 加了这个声明后,里面的代码就全是utf-8格式了
    4. 在有#_*_coding:utf-8*_的情况下,你在声明变量如果写成name=u"大保健",那这个字符就是unicode格式,不加这个u,那你声明的字符串就是utf-8格式
    5. utf-8 to gbk怎么转,utf8先decode成unicode,再encode成gbk

    再说python3

    1. py3里默认文件编码就是utf-8,所以可以直接写中文,也不需要文件头声明编码了,干的漂亮
    2. 你声明的变量默认是unicode编码,不是utf-8, 因为默认即是unicode了(不像在py2里,你想直接声明成unicode还得在变量前加个u), 此时你想转成gbk的话,直接your_str.encode("gbk")即可以
    3. 但py3里,你在your_str.encode("gbk")时,感觉好像还加了一个动作,就是encode的数据变成了bytes里,我操,这是怎么个情况,因为在py3里,str and bytes做了明确的区分,你可以理解为bytes就是2进制流,你会说,我看到的不是010101这样的2进制呀, 那是因为python为了让你能对数据进行操作而在内存级别又帮你做了一层封装,否则让你直接看到一堆2进制,你能看出哪个字符对应哪段2进制么?什么?自己换算,得了吧,你连超过2位数的数字加减运算都费劲,还还是省省心吧。  
    4. 那你说,在py2里好像也有bytes呀,是的,不过py2里的bytes只是对str做了个别名,没有像py3一样给你显示的多出来一层封装,但其实其内部还是封装了的。 这么讲吧, 无论是2还是3, 从硬盘到内存,数据格式都是 010101二进制到-->b'xe4xbdxa0xe5xa5xbd' bytes类型-->按照指定编码转成你能看懂的文字

    总结

    • utf8中一个中文占3个字节
    • python2中utf8转gbk   先decode成unicode 再encode成gbk
    • 只有unicode能encode、decode

    编码应用比较多的场景应该是爬虫了,互联网上很多网站用的编码格式很杂,虽然整体趋向都变成utf-8,但现在还是很杂,所以爬网页时就需要你进行各种编码的转换,不过生活正在变美好,期待一个不需要转码的世界。

    函数的定义

    定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

    特性:

    1. 减少重复代码
    2. 使程序变的可扩展
    3. 使程序变得易维护

    函数的定义主要有如下要点:

    • def:表示函数的关键字
    • 函数名:函数的名称,日后根据函数名调用函数
    • 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
    • 参数:为函数体提供数据
    • 返回值:当函数执行完毕后,可以给调用者返回数据。
    def func(name):#func函数名,name参数
        print('my name is',name)#函数体
    func('hongpeng')#调用func函数

    形参:变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

    实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

    上面的例子中name就是形参,'hongpeng'就是实参

    函数的几种参数

    1.普通参数

    像下面例子中的name,age,job

    2.默认参数

    在定义函数时直接赋值,调用函数如果不指明默认就是定义函数时赋的值,指明的话就是你赋的值,定义时特别要注意默认参数在最后

    def inf(name,age,job,country='CN'):
        print('the information of %s'.center(50,'-')%name)
        print('name:',name)
        print('age:',age)
        print('job:',job)
        print('country:',country)
    inf('hongpeng',21,'ops')
    inf('alex',31,'loser','JP')
    #输出
    --------------the information of hongpeng---------------
    name: hongpeng
    age: 21
    job: ops
    country: CN
    --------------the information of alex---------------
    name: alex
    age: 31
    job: loser
    country: JP

    3.关键参数

    正常情况下,给函数传参数要按顺序,如果一个函数中参数太多或者不想按顺序就可以用关键参数,只需调用时指定参数名即可,好像没什么卵用。。。非固定参数**kwargs在传参数的时候会用到。

    4.非固定参数

    若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数

    *args

    def inf(name,age,job,*args):#*args会把多个传入的参数放入一个元组中
        print(name,age,job,args)
    inf('hongpeng',21,'ops')
    inf1('hongpeng',21,'ops','CN','python')
    #输出
    hongpeng 21 ops ()#因为没有传值,所以args为空
    hongpeng 21 ops ('CN', 'python')

    **kwargs

    def inf(name,age,job,**kwargs):#**kwargs把传入参数放在字典中,所以调用时参数得用关键参数的形式
        print(name,age,job,kwargs)
    inf('hongpeng',21,'ops')
    inf('hongpeng',21,'ops',country = 'CN',lesson = 'python')
    #输出
    hongpeng 21 ops {}
    hongpeng 21 ops {'lesson': 'python', 'country': 'CN'}

    局部变量和全局变量

    在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
    全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序
    当全局变量与局部变量同名时:
    在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
    全局变量最好都用大写
    name = 'alex'
    def inf():
        name = 'hongpeng'
        print('函数里面的name:',name)
    inf()
    print('函数外的name:',name)

    函数里面的name改变并没有影响到外部的name

    如果想在函数里面对全局变量改变,用global,但是一般不会在函数里面去改全局变量的值,so,忘了它吧。

    name = 'alex'
    def inf():
        global name
        name = 'hongpeng'
        print('函数里面的name:',name)
    inf()
    print('函数外的name:',name)
    #输出
    函数里面的name: hongpeng
    函数外的name: hongpeng

    返回值

    1.一旦你的函数经过调用并开始执行,那函数外部的程序就没有办法再控制函数的执行过程,此时外部程序只能等待函数的执行结果
    为什么要等待执行结果?
    因为外部函数要根据函数的返回值来决定下一步怎么走,执行结果就是以return的形式返回给外部程序
    2.return代表一个函数的结束
    3.return可以返回任意数据类型
    4.对于用户角度,函数可以返回任意数量的值,但对于python本身来讲,函数只能返回一个值,多个放在一个元组中
    5.如果函数不加return,默认是返回None
    练习:
    进入购物商城,首先要登录,登录之后访问任意网页都不再需要登录
    def auth():
        username = input("username:").strip()
        password = input("password:").strip()
        #get data from db
        _username = "alex"
        _password = "alex3714"
        if username == _username and password == _password:
            print("passed authentication!")
            # global login_status
            # login_status = True #局部变量
            # print("-->",login_status)
            return True, 1,2
            print("after return ....")
        else:
            return False
    
    
    def home():
        if login_status == True:
            print("welcome to home page")
        else:
            auth()
    def pay():
        if login_status == True:
            print("welcome to pay page")
        else:
            auth()
    
    login_status = auth()
    print(login_status)
    
    
    # print(login_status)
    home()
    pay()
    View Code
    嵌套函数
    name = 'ALEX'
    def name():
        name = 'alex'
        def name2():
            name = 'hongpeng'
            print('3name:',name)
        name2()
        print('2name',name)
    name()
    #输出
    3name: hongpeng
    2name alex

    递归函数

     在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

    def calc(n):
        print(n)
        if n//2> 0:
            calc(n//2)
    calc(10)
    #输出
    10
    5
    2
    1
    def calc(n):
        if n//2> 0:
            calc(n//2)
        print(n)
    calc(10)
    #输出
    1
    2
    5
    10
    View Code

    递归特性:

    1.必须有一个明确的结束条件

    2.每次进入更深一层递归时,问题规模相比上次递归有所减少

    3.递归效率不高,递归层次过多会导致栈溢出

    递归实际应用(二分查找)

    def find(dataset,find_num):
    
        if len(dataset) > 0:
            mid_pos = int(len(dataset)/2)
            if dataset[mid_pos] == find_num:
                print('find the number',dataset[mid_pos])
            elif dataset[mid_pos] > find_num:
                print('going to left side')
                print(dataset[mid_pos])
                find(dataset[0:mid_pos],find_num)
            else:
                print('going to right side')
                print(dataset[mid_pos+1])
                find(dataset[mid_pos+1:],find_num)
        else:
            print("can't find the num")
    data = range(0,10000,5)
    find(data,88)

    匿名函数+map+三元运算

    #匿名函数
    n = lambda x,y:x+y
    print(n(4,5))
    #map函数
    data = map(lambda n:n**2,range(5))
    for i in data:
        print(i)
    #三元运算
    a = 4
    b = 5
    c = a if a >10 else b
    print(c)
    #函数+lambda+map+三元运算
    def
    calc(n): return -n data = map(lambda x:x**2 if x>5 else calc(x),range(10)) for i in data: print(i)

    高阶函数

    变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

    def calc(x,y,f):
        return f(x)+f(y)
    res = calc(4,-5,abs)
    print(res)
    #输出
    9

    内置函数

    abs()绝对值

    all()都为真,True

    any()任意值为真,True

    callable()能否被调用

    chr(98)根据数据找到ascii中对应的字母

    ord('b')根据字母找ascii中的数字

    globals()把当前程序所在内存里的所有数据都以字典形式打印出来

    local()

    power()次方

    frozenset()

    reversed()反转

    round()四舍五入

    slice()

    #slice
    a = range(20)
    pattern = slice(3,8,2)
    for i in a[pattern]: #等于a[3:8:2]
        print(i)

    sorted()

    zip()

    a = [-5,1,3,5,7,9]
    b = [2,4,6,8]
    for i in zip(a,b):
        print(i)
    #输出
    (-5, 2)
    (1, 4)
    (3, 6)
    (5, 8)
  • 相关阅读:
    用上CommonMark.NET,.NET平台终于有了好用的markdown引擎团队
    上周热点回顾(9.21-9.27)团队
    云计算之路-阿里云上:13:43-13:44之间RDS故障影响了全站的正常访问团队
    CentOS6.5下如何正确下载、安装Intellij IDEA、Scala、Scala-intellij-bin插件、Scala IDE for Eclipse助推大数据开发(图文详解)
    spark-2.2.0-bin-hadoop2.6和spark-1.6.1-bin-hadoop2.6发行包自带案例全面详解(java、python、r和scala)之Basic包下的JavaPageRank.java(图文详解)
    spark-2.2.0-bin-hadoop2.6和spark-1.6.1-bin-hadoop2.6发行包自带案例全面详解(java、python、r和scala)之Basic包下的SparkPageRank.scala(图文详解)
    spark-2.2.0-bin-hadoop2.6和spark-1.6.1-bin-hadoop2.6发行包自带案例全面详解(java、python、r和scala)之Basic包下的JavaTC.java(图文详解)
    spark-2.2.0-bin-hadoop2.6和spark-1.6.1-bin-hadoop2.6发行包自带案例全面详解(java、python、r和scala)之Basic包下的SparkTC.scala(图文详解)
    Spark Mllib里数据集如何取前M行(图文详解)
    Spark Mllib里如何将数值特征字段用StandardScaler进行标准化(图文详解)
  • 原文地址:https://www.cnblogs.com/hongpeng0209/p/6014415.html
Copyright © 2020-2023  润新知