函数基础

(一)python基础(三)主要分享的是包括如下几部分:

  • 编码进阶
  • id、is、小数据池
  • 集合和深浅拷贝
  • 文件操作
  • 函数的初识
  • 函数的进阶

(二)具体的分享内容如下:

1.编码的进阶

'''
编码进阶说明:
01 不能编码之间不能相互识别(ASCII码间可以相互转化)
02 字符串加载在内存中的,使用的编码方式为Unicode
03 将加载到内存中的字符串进行数据存储、数据传输时会涉及到编码的转换。主要是进行str和bytes类型的数据的转换。
04 bytes类型只有在传输和存储的数据的时候才会使用
'''

# 01 bytes数据类型:在数据传输、数据存储时会使用到。

#  001 英文字符的表现形式
# str:
    # 形式:s1 = 'Alex'
    # 内存的编码方式:Unicode
# bytes
    # 形式;s1 = b'Alex'
    # 内存中的编码方式;费Unicode
    
#  002 中文字符的表现形式
# str:
    # 形式:s1 = '中国'
    # 内存的编码方式:Unicode
# bytes
    # 形式;s1 = b'\xe4\xb8\xad\xe5\x9b\xbd'
    # 内存中的编码方式;费Unicode
    
    
# 02  字符串的编码与解码
# 001 str-->bytes  编码:encode()
s1 = 'alex'
b1 = s1.encode('utf-8')
b2 = s1.encode('gbk')
print(s1, type(s1))
print(b1, type(b1))
print(b2, type(b2))

# 002 bytes-->str 解码:decode()
b1 = b'\xe4\xb8\xad\xe5\x9b\xbd'
s1 = b1.decode('utf-8')
print(s1)

2.id is 小数据池

'''
说明:
01 id 是判断数据对应的'内存地址',内存地址在python中只是一个标志作用,并不代表该数据在内存中的实际地址(需要在命令窗口下进行验证)
02 == 是判断两个数据对应的值是否相等
03 is 身份运算,判断的是数据的内存地址是否相同(需要子啊命令窗口下进行验证)
04 小数据
(1)作用:一方面是用来节省空间,另一方面是提高性能。
(2)小数据池是在内存中开辟了两个空间,即字符串空间和整型空间,当满足字符串的条件和整型的范围,则无论定义多少个元素都指向同意内存地址。
        1)int: -5 至 256 范围。
        2)str; 满足一定规则的字符串
'''

s1 = '马玉刚'
s2 = '马玉刚'

print(s1 == s2)  # 判断值是否相等

print(id(s1))  # 判断值的内存地址

3.集合和深浅拷贝

'''
集合说明:
01 集合里面的元素必须是不可变的数据类型,集合本身是可变的数据类型。
02 集合是无序的,不重复的。
03 集合的两个作用。
    01)列表去重
    02)关系测试,交集、并集、差集
04 集合的for循环
'''

# 01 集合里的元素必须是不可变的类型。
print({(1, 2, 3), '马玉刚'})
print({[1, 2, 3], {'name': '马玉刚'})  # 列表和字典是不可hash的,所以不能作为集合的元素。

# 02 集合作用:列表去重
l1 = [1, 1, 2, 3, 4, 3, 2, 4, 5, 6]
set1 = set(l1)  # 将列表转换为集合
print(set1)
l1 = list(set1)  # 将集合转换为列表
print(l1)

# 03 集合的作用:关系测试,包括但不限于如下:交集、并集、差集。

# 04 集合的for循环。
set1 = {'alex', 'WuSir', 'barry', '女神', }   # 集合中最后一个逗号有和没有都是一样的, 都不会报错。
for i in set1:
    print(i)  # 迭代输出:alex,WuSir,barry,女神

# 05 内置函数frozenset([iterable]):返回一个冻结的集合,即这个集合不能删除或者条件任何集合李的元素,主要作用是速度快。

set2 = frozenset({1, 2, 3, 4, 7, 6})
print(set2, type(set2))  # 不可变的数据类型   输出结果:frozenset({1, 2, 3, 4, 6, 7}) <class 'frozenset'>
dic = {set2: 666}  # 由于set2是不可变的类型,所以可以做字典的key
print(dic)
for i in set2:
    print(i)


'''
深浅copy说明:
01 赋值运算是指右侧数据在内存中开辟一个空间,如果两个变量由统一数据进行赋值,若数据改变,则两个变量的值同时都变。
02 浅copy:第一层开辟新的内存地址,但是从第二层乃至更深的层来说,共用的都是一个。
03 深copy:复制两个完全独立的数据(多少层都是独立的)。
'''

# 01 赋值运算是指右侧数据在内存中开辟一个空间,如果两个变量由统一数据进行赋值,若数据改变,则两个变量的值同时都变

l1 = ['alex', 'WuSir', 'barry', '女神', ]
l2 = l1  # 赋值运算
l1.append('日天')
print(l1)  # ['alex', 'WuSir', 'barry', '女神', '日天']
print(l2)  # ['alex', 'WuSir', 'barry', '女神', '日天']

# 02 浅copy:第一层开辟新的内存地址,但是从第二层乃至更深的层来说,共用的都是一个。
# 0201 第一层开辟了新的内存地址。
l1 = ['alex', 'WuSir', 'barry', '女神', ]
l2 = l1.copy()
l1.append('泰迪')
print(l1, id(l1))
print(l2, id(l2))

# 0202 从第二层起,共用统一内存地址。
l1 = ['alex', 'WuSir', 'barry', [1, 2, 3]]
l2 = l1.copy()
l1[0] = 'SB'
l1[-1].append('女神')
print(l1, id(l1), id(l1[-1]))  # ['SB', 'WuSir', 'barry', [1, 2, 3, '女神']] 35502472 35503496
print(l2, id(l2), id(l2[-1]))  # ['alex', 'WuSir', 'barry', [1, 2, 3, '女神']] 35537032 35503496

# 03 深copy:复制两个完全独立的数据(多少层都是独立的),即形成两个新的数据相互不影响。
import copy  # 导入系统内存方式。
l1 = ['alex', 'WuSir', 'barry', '女神', ]
l2 = copy.deepcopy(l1)
l1.append('泰迪')
print(l1, id(l1))  # ['alex', 'WuSir', 'barry', '女神', '泰迪'] 42354888
print(l2, id(l2))  # ['alex', 'WuSir', 'barry', '女神'] 42355080

l1 = ['alex', 'WuSir', 'barry', [1, 2, 3]]
l2 = copy.deepcopy(l1)
l1[-1].append('女神')
print(l1, id(l1), id(l1[-1]))  # ['alex', 'WuSir', 'barry', [1, 2, 3, '女神']] 32655752 32655560
print(l2, id(l2), id(l2[-1]))  # ['alex', 'WuSir', 'barry', [1, 2, 3]] 32657032 32656968

4.文件的操作

'''
文件操作说明:
00)文件操作的基本形式:
    f1 = open(r'd:\美女护士老师.txt', encoding='utf-8', mode='r')   # 打开文件
    content = f1.read()
    print(content, type(content))
    f1.close()   # 关闭文件
01 文件操作的3个关键要素。
    01) open():内置函数,用于打开文件
    02) f1:文件句柄形式包括 f1,fh,file_handle,f
    03)f1.close():内置函数,用于关闭打开的文件,文件打开后必须手动关闭,否则会极大的消耗内存(with 情况除外。)
02 文件的操作:r 、r+、w、a
    1)r :读文件,其中open()默认的mode = r,所以要是读文件的时候,可以默认不写。r模式下读有5种形式:
        a)read():全部读取。
        b)read(n):按照 “字符”读取。
        c)readline:按行进行读取。
        d)readlines() 返回一个列表,列表中的每个元素是原文件的一行。
        e) for循环。(***在工作过程中推荐使用for循环来进行读文件,这样可以极大的降低内存的消耗,提高性能)
    2)r+:先读文件后写文件。
    3)w :写文件。
        a)没有文件创建文件写内容。
        b)有文件先清空后写入。
    4)a:文件的追加
        a)没有文件创建文件写入内容。
        b)有文件直接在后面追加。
03 with的可以同时打开多个文件。
04 文件改的操作步骤。
    1)以读的模式打开文件
    2)已写的模式打开一个新的文件
    3)对原文件的内容进行修改,形成新的内容写入新文件
    4)删除原文件
    5)将新文件的文件名重命名为原文件的文件名
05 文件的其他操作
'''

# 01)相对路径和绝对路径
# 绝对路径:从C、D、E等盘开始的路径,比如'D:\马玉刚.txt'
# 相对路径:当前的目录下,同一个文件夹下。

# 02)r模式下读的5种形式:

# 第一种 read() 全部读取
f1 = open('马玉刚', encoding='utf-8')   # encoding 指定文件的读取时使用的编码方式,与encode、decode无关。
content = f1.read()
print(content, type(content))
f1.close()

# 第二种 read(n)  r:模式 按照 字符去读取
f1 = open('马玉刚', encoding='utf-8')
content = f1.read(3)
print(content)
f1.close()

# 第三种 readline() 按行读取,,输入几行即打印出几行。
f1 = open('马玉刚', encoding='utf-8')
print(f1.readline().strip())
print(f1.readline().strip())
print(f1.readline().strip())
f1.close()
print(666)

# 第四种 readlines() 返回一个“列表”,列表中的每个元素是原文件的一行
f1 = open('马玉刚', encoding='utf-8')
content = f1.readlines()
print(content, type(content))
f1.close()

# 第五种 for循环
f1 = open('马玉刚', encoding='utf-8')
for line in f1:
    print(line.strip())
f1.close()

# 03) r+先读后写(后追加)

f1 = open('马玉刚', encoding='utf-8', mode='r+')
content = f1.read()
print(content)
f1.write('666')
f1.write('来了')
print(f1.read())
f1.close()

# 4) w 模式下文件的操作:(1)没有文件创建文件写入内容。(2)有文件先清空后写入。
f1 = open('log1', encoding='utf-8',mode='w')
f1.write('(1)没有文件创建文件写入内容。(2)有文件先清空后写入。')
f1.close()

# 5)a 模式下的文件操作:(1)没有文件创建文件写入内容。(2)有文件直接在后面追加。

f1 = open('log1', encoding='utf-8',mode='a')
f1.write('\n喇叭坏了 fuck')
f1.close()

# 6)文件的常用操作

# a) readable() :是否可读
# b) writable():是否可写
f1 = open('log1', encoding='utf-8',mode='w')
f1.write('又好了....')
if f1.readable():
    print(f1.read())
print(f1.readable())
f1.close()

# c) tell() 告诉你光标的位置(按照字节)
f1 = open('马玉刚', encoding='utf-8')
content = f1.read(3)
print(f1.tell())
f1.close()

# d) seek() 调整光标的位置(按照字节)
f1 = open('马玉刚', encoding='utf-8')
f1.seek(9)
content = f1.read()
print(content)
f1.close()

# 7) 文件的修改
# read() 占用内存
import os   # 引用内置的函数
with open('alex美文', encoding='utf-8') as f1, \   # 如果是多行的话,可以用'\'来进行换行
        open('alex美文.bak',encoding='utf-8',mode='w') as f2:
    old_content = f1.read()
    new_contenet = old_content.replace('alex', 'SB')
    f2.write(new_contenet)
os.remove('alex美文')
os.rename('alex美文.bak','alex美文')

import os
with open('alex美文', encoding='utf-8') as f1, \
        open('alex美文.bak',encoding='utf-8',mode='w') as f2:
    for line in f1:
        new_line = line.replace('SB','alex')
        f2.write(new_line)
os.remove('alex美文')
os.rename('alex美文.bak','alex美文')

5.函数的初识

'''
整体说明:
01 面向过程编程和面向面向对象/函数编程的区别。
    (1)面向过程编程(流水账),代码重复、可读性差。
    (2)面向对象/函数编程的有点是代码可读性高。
02 函数:一个函数封装一个功能
    (1)函数的定义的形式:
            def 函数名():
                函数体
    (2)函数的执行者/调用者:函数名()  # 注意只要是函数名+(),该函数即被调用,调用后才执行函数体,否则不执行函数
         体的内容,函数体的内容执行完成通过return将返回值反馈给函数,完成以上全部操作后才算完成了函数的执行/调用的
         过程。
    (3)返回值return:
            a)函数中遇到return则中止函数。
            b)返回值返回给函数的调用者。
            c)返回值的3种形式。
                1)return  :返回值是None
                2) return 单个值:返回单个值
                3)return 多个值:返回的是有这个多个值组成的元祖
    (4)函数的参数:形参、实参。
    (5)函数的传参形式:
             a) 实参角度:
                1)位置参数 : 从前至后 一一对应,如果不一一对应则进行报错。
                2)关键字传参: 不用按照顺序,一一对应,如果不一一对应则进行报错。
                3)混合传参: 位置参数一定在前面。
            b)形参角度
                1) 位置传参: 按照顺序,一一对应
                2) 默认传参: 如果不传,则默认使用默认参数,传参则覆盖。 常用的会设置默认参数
                3) 动态参数,也叫不定长传参,就是你需要传给函数的参数很多,不定个数,那这种情况下,你就用
                   *args,**kwargs接收,args是元祖形式,接收除去键值对以外的所有参数,kwargs接收的只是键值
                   对的参数,并保存在字典中。
    (6)形参的顺序:位置参数,*args,默认参数,**kwargs
'''

# 01  函数名(): 函数的执行者,调用者
def my_len():
    l1 = [1, 2, 34, 55, 66]
    global c  # 在局声明一个全局变量,定义后局部可以修改,
    c = 0
    for i in l1:
        c += 1
    return c  # 将c返回给函数调用者
my_len()  # 函数的执行者调用者
print(my_len())
print(c)

# 02 返回值return:
# 0201遇到return函数中止,return后的函数语句不执行。
def my_len():
    print(111)  # 111
    print(222)  # 222
    return (1, 2, 3), [12, 4]
    print(333)  # 遇到return后,函数中止,该结果不打印。
ret = my_len()
print(ret, type(ret))  # ((1, 2, 3), [12, 4]) <class 'tuple'>

# 0202
def my_len():
    l1 = [1, 2, 34, 55, 66]
    c = 0
    for i in l1:
        c += 1
    return c
print(my_len())

# 03 函数的传参:将实参赋值给形参,在函数体中执行之后将结果通过return返回。
l1 = [1, 2, 34, 55, 66]
def my_len(s):  # 形参
    c = 0
    for i in s:
        c += 1
    return c
print(my_len('fdskalfdsjflsdajf;lsa'))  # 21
ret = my_len(l1)  # 函数的执行者(实参)
print(ret)  # 5

# 04 实参角度
# 0401 位置参数:位置参数必须按照顺序,一对一,否则会报错,。

# 少一个实参,所以运行的时候报错。
def func1(a, b, c):
    print(a + b)
func1('alex', 'wusir')

# 实参个数和形参个数一一对应,所以,正常运行。
def func1(a, b):
    # if a > b:
    #     return a
    # else:
    #     return b
    return a if a > b else b

def func1(a, b): return a if a > b else b  # 三元运算,是对if else的优化。
print(func1(100, 200))

# 0402 关键字传参:参数一一对应,但是无顺序要求。
def func2(age,name):
    print(name,age)
func2(name='alex', age=73)

# 0403混合传参
def func3(a, b, c, name):
    print(a, b, c, name)

func3(1, 2, 3, name='alex')

# 0404 return说明
# 不带return
def trans_para(a, b, *args, name1='张三', **kwargs):
    print(a)
    print(b)
    print(name1)
    print(args, type(args))
    print(kwargs, type(kwargs))
trans_para("jinxin", 12, [1, 2, 3, 4], [3, 4, ], (1, 4, 7), {"a": "123", "c": 456}, name1='李苹', country="马玉刚",
           name='alex', )  # 函数调用者,函数执行者
#
# # 带有return
def trans_para(a, b, *args, name1='张三', **kwargs):
    return a, b, name1, args, kwargs
print(trans_para("jinxin", 12, [1, 2, 3, 4], [3, 4, ], (1, 4, 7), {"a": "123", "c": 456}, name1='李苹', country="马玉刚",
           name='alex', ))   #  ('jinxin', 12, '李苹', ([1, 2, 3, 4], [3, 4], (1, 4, 7), {'a': '123', 'c': 456}), {'country': '马玉刚', 'name': 'alex'})



# 05 形参角度

# 0501 位置参数
def func1(a,b,c,d):
    print(a,b,c)
func1(1,2,3)

# 0502 默认参数 :
def func2(name,age,sex=''):
    print(name,age,sex)
func2('alex',73,sex='')

def wfile(name,age,sex=''):
    with open('登记表',encoding='utf-8',mode='a') as f1:
        f1.write('{}|{}|{}\n'.format(name,age,sex))

while 1:
    name = input('姓名(输入Q/q退出):')
    if name.upper() == 'Q':break
    age = input('年龄:')
    if name.startswith('1'):
        wfile(name, age)
    else:
        sex = input('性别:')
        wfile(name, age, sex)
#
# 0503 万能参数 *args, **kwargs
# * 的魔性用法
def func4(*args, **kwargs):  # 在函数的定义 * ** 聚合
    print(args)
    print(kwargs)


# 函数执行时 (1) *iterable 打散(2) **dict 打散

def func4(*args, **kwargs):  # 在函数的定义 * ** 聚合
    print(args)  #
    print(kwargs)
l1 = [1,2,3]
l2 = [11,22,33]
l3 = (55,66,77)
dic = {'name':'alex'}
dic1 = {'age':'12'}
# func4(*l1,*l2,*l3)
func4(**dic,**dic1)

func4([1,2,3],[11,22,33],(55,66,77))


# 0504形参的顺序:位置参数、*args、默认参数、**kwargs
def func5(a, b, *args, sex=''):
    print(a)
    print(b)
    print(sex)
    print(args)


print(func5(1, 2, 4, 5, 6, 7, 8, 9))


def func5(a,b,*args,sex='',**kwargs,):
    print(a)
    print(b)
    print(sex)
    print(args)

func5(1,2,4,5,6,7,8,9,sex='')

6.函数的进阶

'''
整体说明:
01 python中的空间
    (01)全局名称空间:存储的是全局(py文件)的变量与值的对应关系。
    (02)临时(局部)名称空间:当函数执行时,会在内存中临时开辟一个空间,此空间记录函数中的变量与值的对应关系,随着函数的结束,临时名称空间而关闭。
    (03)内置名称空间:len、print等都是函数的内置函数等。
02 python中空间的加载顺序: 内置名称空间  ---> 全局名称空间 ---> 函数执行时:临时(局部)名称空间
03 python中的作用域:与python中的空间是讲的是一个事情,只是叫法不同。
    (01)全局作用域:内置名称空间 全局名称空间
    (02)局部作用域:临时(局部)名称空间
04 取值顺序:函数执行时的顺序是:临时(局部)名称空间 ---> 全局名称空间   ---->  内置名称空间;取值时满足“就近原则”取值。
05 函数不执行时不开辟新的空间,只有通过“函数名()”进行函数调用时才开辟一个临时空间,函数执行完成后临时空间关闭。
06  global和nonlocal
    (1)global
        a)局部变量只能引用全局变量但是不能修改,修改进行报错,如果想修改则使用global。
        b)在局部空间可以声明一个全局变量。
        c)变量前增加global可以对全局变量进行修改。
    (2)nonlocal
        a)不能操作全局变量
        b)在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
07 函数的嵌套
08 函数名的应用:
    (1)函数名可以当做变量使用(函数的内存地址就是变量的值)
    (2)函数名可以作为函数的参数
    (3)函数名可以作为函数的返回值
    (4)函数名可以作为容器类型的参数
'''

# 01 函数执行是的取值顺序:临时(局部)名称空间 ---> 全局名称空间   ---->  内置名称空间;取值时满足“就近原则”取值


len = 66
print(len)  # 66
a = 1


def func():
    a = 66

    def func1():
        a = 99
        print(a)  # 99,根据就近原则取值a = 99

    func1()


func()

# 02  global的使用:变量前增加global可以对全局变量进行修改,相当于声明一个全局变量
a = 1


def func():
    global a
    a += 1
    print(a)


func()


def func():
    global a
    a = 1


# print(a)
func()
print(a)

# 03 nonlocal:子名称空间只能引用父名称空间的变量,但是不能修改。
def func1():
    a = 1

    def inner():
        nonlocal a
        a += 1

    print(a)  # 1
    inner()
    print(a) # 2


func1()

# 04 函数的嵌套:通过函数的嵌套来进行函数调用。
def func1():
    print(111)
    def func2()
        print(222)
    print(333)
    func2()
    print(444)
func1()

# 输出结果:111 333 222 444

def func1():
    print(111)

def func2():
    print(222)
    func1()


def func3():
    func2()
    print(333)

func3()

# 输出结果: 222 111 333

# 05)函数名的运用
# 0501 函数名可以当做变量使用
def func1():
    print(111)  # 最后调用函数func1时,输出:111


a = 1
b = a
print(b)  # 首先打印 1

print(func1)  # 其次输出:<function func1 at 0x00000000003E3E18>  (函数名当做变量使用)
f1 = func1
f2 = f1
f2()   # 函数调用者 func1()

# 0502 函数名作为函数的参数

def func1():
    print(111) # 最后输出:111


def func2(x):
    print(x) # 首先输出func1作为变量的值:<function func1 at 0x00000000001D3E18>
    x()   # 通过func1()调用函数func1。

# 0503 #函数名可以作为函数的返回值

def func1():
    print(111)  # 第4步:通过函数输出:111


def func2(x):
    return x  # 第2步:返回func1


ret = func2(func1)  # 第1步: 调用函数func2,参数为func1
ret()  # 第3步:通过func1(),调用函数func1


# 0504 函数名可以作为容器类数据类型的参数(在工作过程中会经常会用到)


def func1():
    print(111)


def func2():
    print(222)


def func3():
    print(333)


def func4():
    print(444)


l1 = [func1, func2, func3, func4]
for i in l1:
    i()  # 循环调用函数进行函数执行

dic = {
    1: func1,
    2: func2,
    3: func3,
    4: func4,
}
while 1:
    choice = int(input('请输入数字:'))
    dic[choice]()  # 函数的调用通过“函数名()”进行函数的调用和执行。

 

posted @ 2018-10-29 11:40  马玉刚  阅读(324)  评论(0编辑  收藏  举报