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. 【ArcGIS for Server】制作并发布GP服务--缓冲分析为例

    https://www.cnblogs.com/d2ee/p/3641279.html https://www.jianshu.com/p/5331fa708fe5 https://www.cnblo ...

  2. LeetCode 237 Delete Node in a Linked List 解题报告

    题目要求 Write a function to delete a node (except the tail) in a singly linked list, given only access ...

  3. 简单的可以跑起来的dubbo例子

    原文地址:https://blog.csdn.net/jingyangV587/article/details/78901937 项目结构: maven项目,内部三个module. <?xml ...

  4. 【JVM】-NO.114.JVM.1 -【JDK11 HashMap详解-3-put-treeifyBin()-AVL】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  5. 《Java程序设计》第二周学习记录(1)

    目录 第2章 基本数据类型与数组 2.1 标识符与关键字 2.2 基本数据类型 2.3 类型转换运算 2.4 输入.输出数据 2.5 数组 参考资料 第2章 基本数据类型与数组 2.1 标识符与关键字 ...

  6. qt 安装包生成

    (Qt Installer Framework)程序简易打包教程 2017年06月19日 14:38:47 carman_风 阅读数:3559 标签: installerqt框架 更多 个人分类: 软 ...

  7. 解决wine中文字体方块或乱码

    从Windows使用字体 如果有一个安装了Windows的分区, 可以通过链接它们来使用其字体. 例如, Windows的C:\盘被挂载在/windows: # ln -s /windows/Wind ...

  8. Zookeeper应用之——队列(Queue)

    为了在Zookeeper中实现分布式队列,首先需要设计一个znode来存放数据,这个节点叫做队列节点,我们的例子中这个节点是/zookeeper/queue. 生产者向队列中存放数据,每一个消息都是队 ...

  9. 软件安全概念:认证 & 授权

    认证 证明你是谁,这个过程就是认证 授权 你能干什么

  10. nginx--service配置

    nginx从今天开始进行相关学习了,包括:1.注册centos的service服务:2.相关的tomcat负载:3.https配置:4.session共享配置 1.注册centos的service服务 ...