python基础知识纵览(下)

python函数

1.函数作用

  • 最大化代码重用和最小化代码冗余
  • 流程的分解

2.函数基本概念

  • def创建对象并赋值给某一变量
## 创建一个函数对象并赋值给fn_name
def fn_name(args1,args2,...,argsN):
    <statements>
  • def是可执行的代码
## 通过if语句判断来做定义函数,def是实时执行的
if test:
    def fn_name():
        <statement>
else:
    def fn_name():
        <statement>
        
## 分配函数对象
myFn = fn_name

## 调用函数
fn_name()
  • return将结果对象发送给调用者
## 函数主体一般都包含return语句
def fn_name(args1,args2,...,argsN):
    ...
    return <value>
  • lambda创建一个对象并将结果返回
## 生成函数对象的表达形式
lambda argument1, argument2,... argumentN : expression using arguments

## lambda注意点
其一,lambda是表达式而不是语句
其二,lambda的主体是一个单个表达式而非语句

## 定义一个正常的函数
def func(x,y,z):
    return x+y+z
    
## 使用lambda表达式
f = lambda x,y,z:x+y+z

## 使用默认参数
f = lambda x=1,y=2,z=3:x+y+z
  • yield向调用者发回一个结果对象并记住离开的地方

生成器函数

## 编写常规def语句并用yield语句一次返回一个结果,在每个结果之间挂起并继续他们的状态
## 定义生成函数
def gensquare(N):
    for index in range(N):
        yield index ** 2        

## 等价于以下的函数
def gensquare(N):
     yield 0 ** 2           ## 函数每次遇到一个yield便会向调用者发送一个返回值并挂起
     ...
     yield (N-1) ** 2

## yield是发送数据不是返回数据
## 调用生成函数,此时的函数是可迭代,可迭代对象定义了一个__next__方法
for i in gensquare(5):      
    print(i,end=":")        

0 : 1 : 4 : 9 : 16 :

生成器表达式

## 列表解析表达式
>>> list = [x**2 for x in range(6)]     
[0, 1, 4, 9, 16, 25]

## 生成器表达式类似上述的列表解析但返回的结果是一个对象而不是一个列表
>>> genrator = (x**2 for x in range(6))
<generator object <genexpr> at 0x1021088e0>

## 执行生成器
>>> next(my_generator)
0 
>>> next(my_generator)
1
...

## 编写一个列表解析器等同于在一个list内置调用中包含一个生成器表达式以迫使其一次生成列表中的所有结果
>>> my_list = list(x**2 for x in range(6))
  • global声明函数中模块级别的变量并进行赋值操作

全局变量

## 全局变量是位于模块文件内部的顶层的变量名
X = 80

## 全局变量如果是在函数内被赋值的话,必须经过声明
def chang_x():
    ## 必须声明
    global X
    X = 90

## 全局变量在函数的内部不经过声明也可以被引用
def reference_x():
    print(X)

## 注意:不同的python文件(模块)之间不要使用『模块对象.属性名』对全局变量进行修改,最好的方式通过函数修改
## a.py
X = 99
def change_x(new):
    global X
    X= new

## b.py
import a
a.change_x(97)

## 访问全局变量的方式
## test.py
var = 99

def local(): 
    var = 0     ## 外面声明的var与函数内没关系,当这个函数执行完毕后,var仍然是99
    
def glob1(): 
    global var  ## 告知函数中var是属于全局变量,直接从全局作用域开始查找,若找不到便会到内置作用域查找,如果还找不到将报错
    var += 1    

def glob2(): 
    import dir1.module  ## dir1与test.py位于同一个目录下,module是dir1下的一个模块,var是module下的全局变量
    dir1.module.var += 1

def glob3(): 
    import sys
    glob = sys.modules['module']    ## 从搜索路径中获取模块,并对该模块全局变量进行操作
    glob.var += 1
  • nolocal声明将要赋值的一个封闭的函数变量,即内嵌一个函数
## 基础语法
def func():
    nonlocal name1, name2, ... # OK here

## nonlocal名称只能存在于嵌套的def语句中,不能出现在模块的全局作用域或def之外的内置作用域
def tester(start): 
    state = start               ## 数据保存在tester函数对象之中
    def nested(label):          ## 返回内嵌的函数对象并且携带了外部函数对象的属性,每次调用将改变外部函数对象的属性state
        nonlocal state          ## 使用nonlocal声明state,state必须是在嵌套函数nested提前定义过
        print(label, state)
        state += 1              
    return nested
    
>>> F = tester(0) 
>>> F('spam') 
spam 0
>>> F('ham')
ham 1
>>> F('eggs')
eggs 2
  • 函数参数是通过赋值(对象引用)传递的
    • 不可变参数通过"值"传递
    • 可变对象通过"指针"进行传递
## 参数传递是通过自动将对象赋值给本地变量名来实现的
def changer(a,b):
    a = 9               # a是值传递,属于当前函数的本地变量
    b[-1] = "spam"      # b是可变对象通过指针传递
    
## 在函数内部的参数名的赋值不会影响调用者
## 改变函数的可变参数的值也许会对调用者有影响
def changer(a,b,c):
    a = 9                   ## 本地变量的值传递不影响调用者
    b[-1] = "spam"          ## 函数改变可变对象所指向的内容值
    c = c[:]                ## 函数内部拷贝副本,不会对调用者影响

## 阻止可变对象在函数改变内容值
- 使用拷贝
- 转成不可变对象,如tuple(list)
  • 参数、返回值以及变量不需要在函数中声明
## python函数没有类型约束,可以传递或返回任意类型参数
def add(a):
    return a ** 2

>>> add(3)
9
>>> add("xiao")
xiaoxiao

python赋值参数匹配顺序

  • 位置:从左至右匹配非关键字参数
def func(a,b,c):
    print a,b,c

>>> func(1,2,3)
1,2,3
  • 关键字参数:通过匹配变量名称分配关键字参数,与位置无关
def func(a,b,c):
    print a,b,c

>>> func(c=3,a=2,b=1)
2,1,3
  • 其他额外的非关键字参数分配到*name元组中
## 任意非关键字参数
def func(*args):
    print(args)     ## 传递进来是元组数据并赋值变量名称为args

## 调用
>>> f1(29,34,4,3,12,13)
29,34,4,3,12,13,
  • 其他额外的关键字参数分配到**name字典中
## 任意关键字参数
def func(**args):
    for key,value in args.items():
        print(key +"-->" + value)

## 调用
>>> f2(name="xiaoxiao",url="https://www.baidu.com")
url--https://www.baidu.com
name--xiaoxiao
  • 使用默认值分配给在头部未得到分配的参数
## 函数定义默认参数值
## 以下函数在定义参数传递的时候就已经错误,自然调用就失败
def fn(name="xiao",age):
    print("the name is "+name+",and the age is "+age)

>>> fn(34)      ## 调用失败
SyntaxError: non-default argument follows default argument

>>> fn(age=34)   ## 调用失败
SyntaxError: non-default argument follows default argument

## 正常的定义方式是没有指定默认参数值在前,有默认参数值的定义在后
def fn(age,name="xiao"):
    print("the name is "+name+",and the age is "+age)

>>> fn(34)          ## 调用正常
>>> fn(age=34)      ## 调用正常
python模块与包

1.模块

模块组成

  • import:使导入者以一个整体获取模块
  • from:允许客户端从一个模块中获取特定的变量名
  • imp.reload:在中止py程序中,提供一种重新载入模块文件代码的方法

模块扮演的角色

  • 代码重用
  • 系统命名空间的划分
  • 实现共享服务和数据

import在模块第一次导入时执行三个步骤

  • 找到模块文件,即搜索模块
  • 编译成位码
  • 执行模块的代码来创建所定义的对象

sys.path:即模块搜索路径

  • 程序的主目录
  • PYTHONPATH目录
  • 标准链接库目录
  • 任何.pth文件的内容

模块编写

  • import将整个模块对象赋值给一个变量名
  • from将一个或多个变量名赋值给另一个模块中同名的对象
## 相同主目录
## module1.py   
def check(num):
    return num>0

## module2.py
import module1
module1.check(9)

## from:把模块文件中的一个或者多个变量名从中复制到当前引用的作用域内,此时无需再通过模块调用
from module1 import check
check(9)

## from *:把模块文件中所有定义好的变量名复制到当前引用的作用域中
from moudle1 import *
check(9)

from与import对等性

from module import name1,name2 
等效于
import module
name1 = module.name1
name2 = moudle.name2
del module

模块文件生成命名空间

  • 模块语句在首次导入时执行
  • 顶层的赋值语句会创建模块属性
  • 模块的命名空间能通过属性__dict__或dir(module)获取
  • 模块是一个独立作用域(本地变量就是全局变量)

重载模块:python内置函数reload()

  • reload会在模块当前命名空间内执行模块文件的新代码
  • 文件中顶层赋值语句会使得变量名换成新值
  • 重载会影响所有使用import读取模块的客户端
  • 重载只会对以后使用from的客户端造成影响
## 使用reload()的时候,模块是预先加载过的
/main
    /dir1
        __init__.py
        /dir2
            __init__.py
            dir2module.py
    test.py
    
## main的主目录加载到搜索路径中
>>> import dir1.dir2.dir2module
dir1 init.....
dir2 init....
dir2 module py ...

>>> reload(dir1.dir2.dir2module)    ## 重新加载dir2module,而不会重新加载dir1和dir2的初始化操作
dir2 module py ...

## 重新加载dir1和dir2
>>> reload(dir1) 
>>> reload(dir1.dir2)

2.包

包的导入

  • 每一个python模块包都必须含有__init__.py文件
  • 增加主目录到包的搜索路径中,即PYTHONPATH或者是.pth文件中
  • 模块搜索路径的项目提供平台特定的目录路径前缀,之后再在import的路径左边添加这些路径

包的执行

  • 包的初始化:导入某个目录时,会自动执行改目录下__init__.py文件中的所有程序代码
  • 模块命名空间的初始化:导入后会变成真实的嵌套对象路径
  • from * 语句的行为:可以在__init__.py定义目录以from * 语句形式导入时,需要导出什么
## 当前目录结构:
dir0
    /dir1
        __init__.py
        a.py
        /dir2
            __init__.py
            b.py
    /module2
        __init__.py
            /module3
                __init__.py
                b.py
    test.py         
dir0称为主目录(__init__.py可有可无),dir1 和 dir2 是模块包,将主目录添加到搜索路径中

## 常规导入
>>> import dir1.dir2.b      ## 导入后会运行并返回一个模块对象
dir1 init.....              ## dir1下的__init__.py
dir2 init....               ## dir2下的__init__.py
dir2 module py ...          ## dir2下的b.py

## 使用from导入
>>> from dir1.dir2 import b     ##  避免每次读取时重新输入路径
dir1 init.....              ## dir1下的__init__.py
dir2 init....               ## dir2下的__init__.py
dir2 module py ...          ## dir2下的b.py

相对包导入作用域

  • 相对导入适用于只在包内导入
  • 相对导入只是用于from语句
  • 术语含糊不清
## 可以使用from语句前面的点号(".")来指定,导入相对于外围的包,
## 这样的导入只是在包内部搜索而非在搜索路径(sys.path)搜索
## 目录结构
dir1
    dir2
        __init__.py
        a.py
    test.py

## test.py下
from .dir2 import a  ## 和test.py相同包路径下的dir2文件夹的a模块的导入

模块查找总结

  • 简单模块通过搜索sys.path路径列表上每个目录查找,从左至右
  • 包是带有一个特殊的__init__.py文件的Python模块的直接目录,可以使用A,B,C目录路径语法导入
  • 同一个包文件中,常规的import语句使用将会通过sys.paths规则搜索,而包中的导入使用from语句以及前面的点号,只是检查包目录
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容