美文网首页
python:基础

python:基础

作者: alan2yang | 来源:发表于2019-02-22 23:23 被阅读2次

自己以前整理的笔记,不太完整,后续会不断更新。。。。


  • [ ] LEGB规则
  • [ ] ​

一、代码规范

1.# 号注释时在其后跟一个空格,解释器遇到#号直接跳过,不运行

2.代码短的情况下,可将注释放在代码后,但注释要与代码至少间隔2个空格

3.''' '''多行注释/块注释,内容全部忽略

4.代码注释不少越多越好,复杂的操作要加上若干行注释,不要描述代码

5.PEP8对Python的代码格式给出了建议

6.赋值语句=左右两边各保留一个空格

7.变量命名:多个字母时用_连接,且都用小写字母--推荐

8.另外一种命名规则--驼峰命名法:大驼峰、小驼峰

9.代码中的缩进tab和空格不要混用

10.模块命名要求与变量命名要求一致

二、运行原理

  1. 程序运行完后为程序分配的内存空间清零,数据清除
  2. 主程序中变量名第一次出现才是定义变量,后续再次出现是直接使用变量
  3. 程序运行的三大流程:顺序,分支,循环

三、变量

01.变量的引用

  • 变量和数据是分开存储的
  • 数据保存在内存中某个位置,通过地址找到
  • 变量保存着数据在内存中的地址
  • 变量中记录数据的地址叫引用

_xx:单前置下划线变量,当作为模块导入其他程序中时,该变量不可访问

__xx:双前置下划线变量,私有属性或方法,子类无法继承和使用

__xx__:前后双下划线,魔法方法或属性

xx_:单后置下划线,用于避免与python关键词冲突

变量作用域

LEGB规则

使用id( )函数可查看变量中所保存的数据的地址,十进制输出

python中函数的 实参/返回值 都是是靠 引用 来传递来的

02.可变类型数据和不可变类型数据

  • 不可变数据:数字、字符串、元组
  • 可变数据:列表、字典、集合

Tips:

  1. 字典的key只能是不可变数据,内部进行了hash(key)运算,输入的key必须是不可变类型的数据
  2. 可变数据的内容变化通过方法实现
  3. 如果给一个可变数据类型的变量重新赋值相同类型的数据,引用会修改
# 两个a的id不同

a = [1,2]
print(id(a))

a = [1,2]
print(id(a))

# b,c的id相同
b = 1
print(id(b))

c = 1
print(id(c))

03.局部变量和全局变量


x = 1
def func(x):
    print('x is ', x)
    x = 2
    print('local x is', x)

func(x)
print('global x is', x)

# 输出
# x is 1
# local x is 2
# global x is 1

  1. 全局变量
    为了保证所有的函数都能够正确使用到全局变量,应该 将全局变量定义在其他函数的上方
    全局变量 是在 函数外部定义 的变量(没有定义在某一个函数内),所有函数 内部 都可以使用这个变量,但不能使用=修改 ,可以使用方法进行修改

若要在函数内修改全局变量,需要先对变量进行global声明 ,再进行重新赋值

x = 1

def func():
    # print(x)      # 用global 定义全局变量前不能调用,否则报错
    global x
    print('x is ', x)
    x = 2
    print('local x is', x)

func()
print('global x is', x)
  1. 局部变量
    函数执行结束后,函数内部的局部变量,会被系统回收
  • 若函数内的局部变量名与全局变量名相同,且进行了赋值操作,实质上是新建了一个变量,只不过和全局变量名相同而已
  • 其他注意事项见5-2

局部变量的生命周期

  • 所谓 生命周期 就是变量从 被创建被系统回收 的过程
  • 局部变量函数执行时 才会被创建
  • 函数执行结束后 局部变量 被系统回收
  • 局部变量在生命周期 内,可以用来存储 函数内部临时使用到的数据

注意
函数执行时,需要用到变量时 会:

  1. 首先查找函数内部 是否存在 指定名称 的局部变量如果有,直接使用
  2. 如果没有,查找 函数外部 是否存在 指定名称 的全局变量如果有,直接使用
  3. 如果还没有,程序报错!

全局变量与局部变量之间的一些注意事项:

  1. 在 global 中出现的名字不能在global 之前的代码中使用。
  2. 在 global 中出现的名字不能作为形参, 不能作为循环的控制对象, 不能在类定义, 函数定义, import语句中出现。
hehe=6
def f():
    print(hehe)        # 不能在赋值前调用  why?????
    hehe=2
f()
print(hehe)

# 报错:UnboundLocalError: local variable 'hehe' referenced before assignment

x = 1

def func():
    print(x)      # 用global 定义全局变量前不能调用,否则报错   why?????????????
    global x
    print('x is ', x)
    x = 2
    print('local x is', x)

func()

# 报错:SyntaxError: name 'x' is used prior to global declaration

四、循环

  1. 使用continue时要注意修改判断条件
  2. break和continue只对当前循环有效

五、函数

  1. 封装
  2. 重用
  • 函数定义后不调用则不执行
  • 定义函数体上方应和其他代码(包括注释)保留两行空行

函数中变量的生命周期????????

5-1 函数参数类型

1.缺省参数/默认参数

  • 一般放在形参列表的最后面
  • 定义函数时,位置参数要放在默认/缺省参数前,否则语法错误
  • 默认参数必须是不可变对象,若是可变对象则会出现问题

如默认参数为列表、字典或大多数类的实例,函数在后续调用中会记录前面传递的参数


def f(a, L = []):
    L.append(a)
    return L


print(f(1))   # [1]
print(f(2))   # [1,2]
print(f(3))   # [1,2,3]

# 改善方法
def fun(a, li=None):
    if li is None:
        li = []
    li.append(a)
    return li

默认参数在函数定义时就被解析,如下:

i = 5

def f(arg=i):
    print(arg)

i = 6
f()
# 结果:
# 5

2.可变参数/多值参数/收集参数

函数接收的参数个数不确定时,使用多值参数

  • 放在位置参数后,默认参数/关键字参数前
  • 若定义函数时,形参位置没有按照上条执行,也可通过关键字参数来赋值

两种类型:

  1. 形参名前加*,接收为元组
    传入的数据被打包成元组,但不包含赋值映射对

  2. 形参名前加**,接收为字典
    将传入的key=value值打包成字典

def demo1(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)

demo1(1, 2, 3, 4, n=1, m=2, st='hello')

# 运行结果
# 1
# (2, 3, 4)
# {'n': 1, 'm': 2, 'st': 'hello'}

拆包
一个问题:若某变量中保存有一个列表或字典,该如何将其内容传入函数?

def demo2(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)


a = (1, 2, 3, 4)
b = {'name': 'xm', 'age': 18}
demo2(1, a, b)
# a,b都传入了args中,kwargs为空
# 1
# ((1,2,3,4),{'name': 'xm', 'age': 18})
# {}

以上程序并没有达到预期,这时需要用到拆包:
在对应的实参名前加上对应的*即可

# 其效果类似于关键字参数,只不过是通过*来识别
def demo3(num, *args, **kwargs):
    print(num)
    print(args)
    print(kwargs)


a = [1, 2, 3, 4]
b = {'name': 'xm', 'age': 18}
demo3(1, *a, **b)
# 1
# (1,2,3,4)
# {'name': 'xm', 'age': 18}

总结:!!!!!!!
以下结论也适用于**,只不过1.**后的数据类型对应的是映射对象(map),2.将映射对象保存在字典中

def f(**a):
    print(a)

f(m=1, n=2)
# {'m':1,'n':2}

所以,*和**其实可以起到过滤数据的作用,*后的数据类型必须是可迭代对象,**后的数据类型必须是映射对象;而当**kwargs作为形参接收数据时,可传入的数据类型必须是map对象,而*args没有限制。

1.可迭代对象前加*的效果

# *后跟可迭代对象,结果是将可迭代对象拆开为单个元素
print(1, 2, 3)
# 1 2 3
print(*[])
#
print(*[1, 2, 3])
# 1 2 3
print(*())
#
print(*(1, 2, 3))
# 1 2 3

print(*'hello')
print('h', 'e', 'l', 'l', 'o')
# h e l l o

print(*{'name': 'xm', 'age': 18})
print('name', 'age')
# name age

print(*{1, 2, 3})
# 1 2 3

2.变量名前加*的效果

# 无论传入的数据个数及类型,最终以元素保存在元组中,结合1中的例子理解
def f(*a):
    print(a)

f(1, 2)
# (1,2)


def f2(*b):
    print(b)
    
f2((1, 2), [1, 2, 3], 1)
# ((1,2),[1,2,3],1)


def f3(*c):
    print(c)

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
x='hello'
f3(*x)
# ('h', 'e', 'l', 'l', 'o')
# *-* coding:utf-8 *-*


def test1(a, b, *args, **kwargs):
    print(a)
    print(b)
    print(args)
    print(kwargs)


def test2(a, b, *args, **kwargs):
    print(a)
    print(b)
    print(args)
    print(kwargs)
    print('-------------')
    # test1(a, b, args, kwargs)  # args和kwargs是两个变量被打包进test1中的元组参数中
    test1(a, b, *args, **kwargs)  # 


test2(1, 2, 3, 4, 5, 6, h='hello', t=1)

3.关键字参数

调用函数时,在函数括号中直接给形参赋值,不讲顺序
当函数的形参有多个缺省参数时,可通过关键字参数进行赋值

def mutable(name, action):
    print(name+'->'+action)


mutable(action='change the world!', name='yl')

5-2 函数参数与局部变量

针对局部变量:

  • 无论传递的参数是可变还是不可变,只要在函数内部对参数使用 赋值语句=,会在函数内部 修改 局部变量的引用不会影响到外部变量的引用
  • 如果传递的参数是 可变类型,在函数内部,使用 方法 修改了数据的内容,就会影响到外部的数据
  • 可变类型变量调用+=效果等同于.extend( )方法
def demo4(num, num_list):
    print('函数内部开始:')
    num += num
    # num = num + num     # 两种方式效果相同,num的id都有变化(数字是不可变对象,只能重新创建),全局变量数字不变

    num_list += num_list           # 列表id不变(列表是可变对象,在原来的基础上更改,效果等同于.extend()),改变全局变量列表

    # num_list = num_list + num_list  # 列表id变化(列表相加产生新的列表),相当于新建一个变量

    print(num)
    print(num_list)
    print('函数内部结束.')


gl_num4 = 9
gl_list = [1, 2, 3]
demo4(gl_num4, gl_list)
print(gl_num4, gl_list)
def mutable(num_list):
    # num_list = [1, 2, 3]
    num_list.extend([1, 2, 3])  # => num_list += [1, 2, 3]
    
    print(num_list)


gl_list = [6, 7, 8]
mutable(gl_list)
print(gl_list)

# 结果
# [6, 7, 8, 1, 2, 3]
# [6, 7, 8, 1, 2, 3]

5-3 递归

函数调用自身的编程技巧

  • 递归要有出口,这个出口一般是满足一定条件时,不再调用函数
  • 递归要有返回值
    使用递归的一般方法:
  1. 从一般到特殊,从大概到具体,最后的出口一般是最小值
  2. 假设函数(n-1)的功能可以实现

特点:
每次递归都是重新调用函数,极耗内存

相关文章

网友评论

      本文标题:python:基础

      本文链接:https://www.haomeiwen.com/subject/nkzyyqtx.html