1,函数的参数

1.1,查看函数的参数类型

def run(a, *args, b, **kwargs):
return a + b

可以通过如下方式查看参数类型:

import inspect
k = inspect.signature(run)
for i, j in k.parameters.items():
print('{:7}:'.format(i) , j.kind)

输出结果为:

a        : POSITIONAL_OR_KEYWORD
args : VAR_POSITIONAL
b : KEYWORD_ONLY
kwargs : VAR_KEYWORD

含义如下:

POSITIONAL_OR_KEYWORD:位置参数或者关键字参数,可以用位置参数或者关键字参数方式传参

VAR_POSITIONAL:可变位置参数,*args

KEYWORD_ONLY:仅限关键字参数,*args或者*后面的,只能用关键字参数方式传参

VAR_KEYWORD:可变关键字参数,**kwargs

POSITIONAL_ONLY:目前不支持

备注:

*args是最后一个位置参数,即*args后面的都是“仅限关键字参数”

**kwargs是最后一个参数,即**kwargs后面不允许再跟参数

1.2,传参方法

位置参数必须在关键字参数前面!

def test(x, y,z)
.......

传参:

位置参数:test(a, b, c)  
关键字接收:test(y=a, x=b, z=c)   # 关键字参数,可颠倒次序
混合:test(1, z=2, y=6) # 位置参数必须在关键字参数前面,后面2个可以颠倒

1.3,*args,数量可变位置参数

args:序列

*args:  序列中的值

def test(x, *args):
    print(x, *args) # 1,2,3
    print(x, args)  # 1,(2,3)
test(1,2,3) # 或test(*[1,2,3])

  

1.4,**kwargs,数量可变的关键字参数

kwargs:字典

*kwargs: 字典的key

**kwargs:字典的键值对

def test(**kwargs):
    print(kwargs) #  {'name': 'guxh', 'age': 18}
    print(*kwargs) # name age
    print(kwargs['name']) # 'guxh'
test(name='guxh', age=18) # 或test(**{'name':'guxh', 'age':18})

1.5,只接受仅限关键字参数

*后面的是仅限关键字参数:

def test(x, *, y):
print(x, y) test('a', 'b') # TypeError
test('a', y='b') # OK

*args后面的是仅限关键字参数:

def test(*args, y):
print(*args, y) test('a', 'b') # TypeError
test('a', y='b') # OK

  

1.6,特殊传参

组合传参,如果name用关键字参数传参,则age必须用关键字参数传参,因为位置参数必须在关键字参数前面。

def test(name, age=18, *args, **kwargs):
print(name) # 位置参数或关键字参数,'guxh'
print(age) # 位置参数或关键字参数,34
print(args) # 可变位置参数,()
print(kwargs) # 可变关键字参数,{'sex': 'f', 'hobby': 'python'}
test('guxh', 34, sex='f',hobby='python')
test(name='guxh', age=34, sex='f',hobby='python')

序列传参,字典传参:

def test(x, y):test(*序列),或test(**字典)

def test(*args) : test(*序列)

def test(**kwargs) :test(**字典)

2,防御可变参数

python的传参是按引用传参,但是函数对传入的参数进行修改以后:

可变参数:例如列表/字典,会就地修改,实际相当于传统的"按引用传参"

不可变参数:例如数值/字符串/远组,会重新开辟内存,结果相当于传统的"按值传参"

2.1,不可变参数传参

函数或类,在改变x之前,x的id与实参a的id完全一样,但是改变后就不一样了,也就是x发生改变时不会影响到实参a,效果相当于传统的按值传参。

函数传参:

def run(x):
print(id(x)) # 1591569856
x += 1
print(id(x)) # 1591569888 a = 0
run(a)
print(a, id(a)) # 0, 1591569856

类的实例化传参:

class Foo:

    def __init__(self, x):
self.x = x
print(id(self.x)) # 1591569856
self.x = self.x + 1
print(id(self.x)) # 1591569888 a = 0
print(id(a)) # 1591569856
f = Foo(a)

2.2,可变参数

函数或类,对x的改变会影响到实参a,效果相当于传统的按引用传参。

函数传参:

def run(x):
x.append(1) a = []
run(a)
print(a) # [1]

类的实例化传参:

class Foo:

    def __init__(self, x):
self.x = x
self.x.append(1) a = []
f = Foo(a)
print(a) # [1]

因此如果不想改变原来的a,可以用浅拷贝或深拷贝:

class Foo:

    def __init__(self, x):
self.x = list(x)

 2.3,可变参数作为默认值的问题

如果想实现对一个输入列表添加一个1,当没有输入列表时,创建一个空列表并添加1,会发生如下问题:

函数:

def run(x=[]):
x.append(1)
return x a = [1, 2, 3]
print(run(a)) # [1, 2, 3, 1],有参数时表现正常
print(run()) # [1],第一次run也正常
print(run()) # [1, 1],第二次run出错了,返回的是有2个1的列表

类的实例化传参:

class Foo:

    def __init__(self, x=[]):
self.x = x
self.x.append(1)

根据不同打印顺序,结果不一样:

f1 = Foo()
f2 = Foo()
print(f1.x) # [1, 1]
print(f2.x) # [1, 1]
f1 = Foo()
print(f1.x) # [1]
f2 = Foo()
print(f2.x) # [1, 1]

实际上f1和f2实例共享了同一个列表,所以都完成实例化后打印的值完全一样。

解决方法是函数或类有可变参数作为默认值时用None:

def run(x=None, y=None):
x = [] if x is None else x
y = {} if y is None else y # requests框架使用了这2句
x.append(1)
y.update({'a': 1})
return x, y

3,高阶函数

3.1,高阶函数

满足下面两个条件之一的就叫高阶函数:

1)一个函数当作参数传给另外一个函数(参数有函数)

2)函数的返回值中包含函数(返回有函数)

3.2,回调函数

回调本质上就是高阶函数的第一个定义场景。

函数A作为参数传给另外一个函数B,涉及三个角色:中间函数A,回调函数B,中间函数A的调用者(一般是主程序)。

如果回调函数想保存额外状态,可以用基于类、闭包、协程、functools.partial、lambda等方式实现。

简单的回调函数:

def add(x, y):              # 回调函数
print(x + y) def fun(x, y, callback): # 中间函数
return callback(x, y) if __name__ == '__main__': # 中间函数调用者
fun(1, 2, callback=add)

保存额外状态的回调 — 基于类:

class Foo:
def __init__(self):
self.s = 0 # 额外状态s
def add(self, x, y):
self.s += 1
print('第{}次相加结果:{}'.format(self.s, x + y)) def fun(x, y, callback):
return callback(x, y) if __name__ == '__main__': # 中间函数调用者
f = Foo()
fun(1, 2, callback=f.add) # 第1次相加结果:3
fun(3, 4, callback=f.add) # 第2次相加结果:7

保存额外状态的回调 — 基于类 + functools.partial / lambda:

class Seq:         # 保存额外状态的类
def __init__(self):
self.seq = 0 def fun(x, y, callback):
return callback(x, y) def add(x, y, s):
s.seq += 1
print('第{}次相加结果:{}'.format(s.seq, x + y)) if __name__ == '__main__':
s = Seq()
fun(1, 2, callback=partial(add, s=s))
fun(3, 4, callback=partial(add, s=s))
# 用lambda替代functools.partial
# fun(1, 2, callback=lambda x, y: add(x, y, s))
# fun(3, 4, callback=lambda x, y: add(x, y, s))

保存额外状态的回调 — 基于闭包:

def make_add():
s = 0
def add(x, y):
nonlocal s
s += 1
print('第{}次相加结果:{}'.format(s, x + y))
return add def fun(x, y, callback):
return callback(x, y) if __name__ == '__main__':
add = make_add()
fun(1, 2, callback=add)
fun(3, 4, callback=add)

保存额外状态的回调 — 基于协程:

def make_add():
s = 0
while True:
x, y = yield # 不产出值,只接收值(接收值在yield左边,产出值在yield右边)
s += 1
print('第{}次相加结果:{}'.format(s, x + y)) def fun(x, y, callback):
return callback((x, y)) # 协程只能接受一个参数,因此改为发送元组 if __name__ == '__main__':
add = make_add()
next(add)
fun(1, 2, callback=add.send) # 往协程发送数据是send
fun(3, 4, callback=add.send)

4,常用内置函数

4.1,匿名函数lambda

调用方法:

>>> fn = lambda x:x*3
>>> fn(3)
9
>>> (lambda x:x*3)(3)
9

lambda y: x + y,其中输入参数y可变,x在运行时才绑定,注意以下代码的区别:

funs1 = [lambda x: x + n for n in range(5)]
for f in funs1:
print(f(0), end=' ') # 4 4 4 4 4
funs2 = [lambda x, n=n: x + n for n in range(5)]
for f in funs2:
print(f(0), end=' ') # 0 1 2 3 4

4.2,计算

1)sum:求和,归约函数,归约函数可以直接结合生成器表达式,避免创建临时列表

nums = [1, 2, 3, 4, 5]
s = sum(x*x for x in nums) # 55,如果nums很大,用列表推导会有很大开销

2)max:最大值,归约函数

3)min:最小值,归约函数

4)round:保留小数位数

5)divmond:相除,返回商和余

6)eval

7)exec

8)hash:哈希

9)id:获取ID

10)int / float / hex / oct / bytes / char / bin / chr / ord : 类型转换

11)pow:次方

4.3,检测

1)all:全部为真返回True,否则返回False,归约函数

2)any:任意为真返回Ture,否则返回False,归约函数

3)bool:判断True or False

4)callable:判断是否可调用

5)isinstance:判断类

6)issubclass:判断子类

7)type

class Human:
pass class Male(Human):
pass m = Male()
print(isinstance(m, Human)) # True
print(isinstance(m, Male)) # True
print(issubclass(Male, Human)) # True
print(type(m)) # <class '__main__.Male'>,如果是import,__main__显示module名

4.4,面向对象

1)super:继承父类

2)vars:返回所有属性名,相当于self.__dict__?

3)setattr / delattr:设置属性 / 删除属性

4)dir:看object部分方法

4.5,迭代

1)iter:获取iterator,iter()可以加哨符值取代while

2)zip:两个序列合起来

3)enumerate:获取index和value

4)map:返回iterator

m = map(lambda x: x * 2,  [1, 2, 3])
print(list(m))
print(dir(m)) # 含有'__iter__', '__new__'
print(type(m)) # <class 'map'>
print(type(iter(m))) # <class 'map'>,iterator的__iter__是return self

5)filter:返回iterator

print(list(filter(lambda x: x > 1, [1, 2, 3])))   # [2, 3]
print(list(filter(None, ['', None, 1, 'a']))) # [1, 'a']

6)range:返回iterable

r = range(10)
print(dir(r)) # 含__iter__,但不含__next__
print(type(r)) # <class 'range'>
print(type(iter(r))) # <class 'range_iterator'>,iterable的__iter__是return iterator

4.6,数据类型

1)tupple,list,dict,set,frozenset:转换为元组/列表/字典/集合/不可变集合

2)slice:切片

3)sort / sorted:排序

4)reversed:反向

4.7,文本

1)str

2)repr

3)replace:替换

4)strip:去除空格

5)format

name = 'guxh'
age = 20
print("my name is " + name + ", age is " + str(age))
print("my name is %s, age is %s" % (name, age))
print("my name is {}, age is {}".format(name, age))
print("my name is {0}, age is {1}".format(name, age))
print("my name is {name}, age is {age}".format(name=name, age=age))
print("my name is {name}, age is {age}".format(**{'name': name, 'age': age}))

格式化参数:

^, <, > 分别是居中、左对齐、右对齐,后面带宽度,分别等效于center, ljust, rjust。

: 号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。

+ 表示在正数前显示 +,负数前显示 -;  (空格)表示在正数前加空格

b、d、o、x 分别是二进制、十进制、八进制、十六进制

eg:>右对齐,@缺失部分用@填充,18固定宽度,','千分位,'.2'浮点精度2,f浮点数声明

'{:@>18,.2f}'.format(70305084.0)   # 输出@@@@@70,305,084.00

6)文本对齐

>>>text = 'hello world'
>>>text.center(20, '*') # 等效format(text, '*^20s'), '{:*^20s}'.format(text)
'****hello world*****'
>>>text.ljust(20, '*') # 等效format(text, '*>20s'), '{:*>20s}'.format(text)
'hello world*********'
>>>text.rjust(20, '*') # 等效format(text, '*<20s'), '{:*<20s}'.format(text)
'*********hello world'

4.8,显示交互

1)print:打印,end指定结束换行符

>>> for i in range(5):
... print(i, end=' ')
0 1 2 3 4  

读取文件时有默认的换行符号,加上print自动产生的换行符,就会产生空行,可以用end去除空行:

with open('text.txt') as f:
for line in f:
print(line, end='')

sep指定间隔,join()只能合并同类型,print+sep可以合并不同类型

>>>print(*list('abcd'), sep='#')
a#b#c#d

2)保存内容到f文件

print('hello world', file=f)

4.9,文件IO

打开文件:

open()函数返回的是个iterator

>>>from collections import abc
>>>f = open('text.txt')
>>>isinstance(f, abc.Iterator)
True

  

参数说明:

  • t:文本,默认
  • r :读,默认
  • w:写,有同名文件覆盖,无同名文件新建
  • a :追加,有同名文件追加,无同名文件新建
  • r+ :  读写(读模式 +写模式/追加模式),写入时和指针指向第几行没有关系,python3总是追加到最后面
  • w+ :没什么用!写读(先创建文件再往里面写),文件不存在会创建,存在就覆盖,和w一样比较危险
  • a+:  比较常用,追加模式 + 读模式,即附加了读的a追加模式(相当于r+a),可以读,也可以追加到最后
  • rb,wb,ab :二进制的基本操作,python3里以rb打开以后无需encode到bytes类型
  • rb+, wb+, ab+ : 二进制的读写操作
  • x:文件不存在时才写入,可以省略os.path.exists判断
  • encoding:编码
  • newline:python会自动将系统换行符(unix是\n,windows是\r\n)转换成\n,设置newline=‘’可以取消自动转换

 

常用方法:

f:是iteraotr,可以逐行打印,但无法获取下标

for i in f:
print(i)

f.read() :一次性全部读取所有内容,注意只能读一次,读第二次会为空

f.readline()  :逐行读取,读5行可以:

for i in range(5):  
print(f.readline())

f.readlines()  :逐行读取所有内容,可以打印所有,f.readlines()和list(f)结果是一样的

for i in f.readlines() :
print(i)

f.tell():返回文件句柄当前指针指向的位置,指针位置是根据字符串确定的,不是根据行数确定的。

f.seek():返回到指针位置,例如f.seek(0),回到指针0的位置,f.seek()一般配合f.tell()使用,f.tell()确定指针位置,f.seek()回到指针位置。

f.encoding:获取文件编码

f.name():获取文件名

f.buffer

f.fileno():打印文件句柄在内存中的位置

f.isatty():判断是否是一个终端设备

f.seekable():判断文件是否可以移回去

f.writeable():判断文件是否可写

f.flush():刷新,写一句语句后不一定马上写到硬盘上,实际是等积满一定内容后再写到硬盘上,flush可以实时刷到硬盘上

# CMD写文件刷新
f = open('test.txt', 'w')
f.write('hello world 1 \n') #此时去打开文件发现还没有写入
f.flush() # 此时去打开发现已写入
f.close()
# 打印进度条:
import(sys)
import(time)
for i in range(50):
sys.stdout.write('#')
sys.stdout.flush()
time.sleep(0.1)

f.truncate():不写参数就清空

f.truncate(10)   # 从开头截断至10
f.seek(10);   # 从第10个字符开始,往后截断至10
f.truncate(10)

f.writelines(s):s是个iterable,相当于:

for i in s:
f.write(i)

f.readinto(buff):将二进制数读取到可变缓冲区中

  

修改文件内容

  • 方法一,读到内存里修改
  • 方法二,修改内容,写到新文件中

读写压缩文件

  • gzip.open:gz
  • bz2.open:bz2

4.10,其他函数

1)globals:返回所有key,value

5,其他

5.1,函数注释

可以对函数的参数类型,返回类型,做注释:

def fun(x: int, y: int) -> int:
return x + y

5.2,exec和eval

exec:执行复杂的python代码,无返回结果(相当于JavaScript中的eval)

eval:计算单个表达式的值,有返回结果

guxh的python笔记二:函数基础的更多相关文章

  1. 8.python笔记之面向对象基础

    title: 8.Python笔记之面向对象基础 date: 2016-02-21 15:10:35 tags: Python categories: Python --- 面向对象思维导图 (来自1 ...

  2. guxh的python笔记一:数据类型

    1,基本概念 1.1,数据类型 基本数据类型:字符串,数字,布尔等 引用数据类型:相对不可变(元组),可变(列表,字典,集合等) 基本数据类型存放实际值,引用数据类型存放对象的地址(即引用) ==:判 ...

  3. Python:笔记(2)——函数与模块

    Python:笔记(2)——函数与模块 Python函数 关于函数 1.我们可以使用Help来查看函数的帮助信息 2.调用函数的时候,如果传入的参数数量或者类型不符合均会报错. 3.函数名其实就是一个 ...

  4. Python进阶(二)----函数参数,作用域

    Python进阶(二)----函数参数,作用域 一丶形参角度:*args,动态位置传参,**kwargs,动态关键字传参 *args: ​ 动态位置参数. 在函数定义时, * 将实参角度的位置参数聚合 ...

  5. python学习总结 --函数基础

    函数基础 ### 函数简介 - 定义:具有特定功能的一段代码 - 优点: - 可以减少代码的重复书写 - 可以将功能的实现着和使用者分开,可以提高开发效率 - 分类: - 库函数:print.inpu ...

  6. Python学习day9 函数Ⅰ(基础)

    函数Ⅰ(基础) 三目运算 基本结构 v =  前面  if 条件 else 后面    #条件为真v=前面,条件为假v=后面.​#等同于if 条件: v = '前面'else:    v = '后面' ...

  7. Python笔记(二)

    python笔记 函数式编程 函数 函数是Python内建支持一种封装(将大段代码拆成函数) 通过函数的调用,可以将复制的任务分解. 函数式编程(Functional Programming) 计算机 ...

  8. python3精简笔记(二)——函数

    函数 下面的地址可以查看函数: https://docs.python.org/3/library/functions.html 也可以在交互式命令行通过help()查看函数的帮助信息. 如: > ...

  9. Python学习笔记二--函数

    1.使用global语句定义全局变量 2.默认参数 默认参数值应该是不可变的.注意: 只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的 ...

随机推荐

  1. [qemu] 差分盘使用

    我要装好多台同样配置的虚拟机.比如10台CentOS7, 各自有不同的配置. 这样的话装10台kvm虚拟机,特别的浪费空间,image文件相互迁移的话也不方便. 这个时候可以选择差分盘:就是先装一个标 ...

  2. python中的*args和**kw

    学习python装饰器decorator的时候遇到*args和**kw两种函数值传递. 在python中定义函数,可以使用一般参数.默认参数.非关键字参数和关键字参数. 一般参数和默认参数在前面的学习 ...

  3. Spring MVC原理及配置详解

    Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单.这些控制 ...

  4. 转换编码utf-8

    用这个enca -x utf-8 * 或者是 filename,还有别的方法,参见:https://blog.csdn.net/a280606790/article/details/8504133 我 ...

  5. Windows下安装MySql5.7(解压版本)

    Windows下安装MySql5.7(解压版本) 1. 官方地址下载MySql Server 5.7 2. 解压文件到目录d:\Soft\mysql57下 3. 在上面目录下创建文件my.ini,内容 ...

  6. halcon脱离hdvp运行

    halcon如何脱离HDevelop运行:第一种方式(测试多台电脑全部正常):(推荐)使用本站开发的脱机修复助手:https://www.51halcon.com/thread-1217-1-1.ht ...

  7. 学习使用scrapy itemspipeline过程

    开始非常不理解from https://www.jianshu.com/p/18ec820fe706 找到了一个比较完整的借鉴,然后编写自己的煎蛋pipeline 首先在items里创建 image_ ...

  8. 20155228 2017-11-19 实现mypwd(选做,加分)

    20155228 2017-11-19 实现mypwd(选做,加分) 题目和要求 学习pwd命令 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 实现mypwd 测试mypwd ...

  9. json-server基本使用

    **一.前后端并行开发的痛点** 前端需要等待后端开发完接口以后 再根据接口来完成前端的业务逻辑 **二.解决方法** 在本地模拟后端接口用来测试前端效果 这种做法称之为构建前端Mock **三.js ...

  10. vs2017 exe在Linux上运行

    1:将vs .netcore控制台项目发布打包(比如文件名为:demo2core.zip,以下会用到) 2:使用XShell软件连接Linux a.在linux上使用命令  id addr找出ip地址 ...