Python基础2 - 函数

函数

作用: 
  1. 减少重复代码
  2. 方便修改, 更易扩展
  3. 保持代码一致性
 

参数

形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
 
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
 
位置参数: 按照位置给形参传值
 
关键字参数: 无需按位置,但关键字实参必须在位置实参后面
 
默认参数: 形参在定义时就已经为其赋值
 
非固定参数: 函数在定义时不确定用户想传入多少个参数,就可以使用
 
def print_info(name, age, sex="male", *args, **kwargs):  # 形参  sex="male"为默认参数  *args会把多传入的位置参数变成一个元组形式  **kwargs会把多传入的关键字参数变成一个dict形式
    print('Name: %s'%name)
    print('Age: %d'%age)
    print('Sex: %s'%sex)
 
    print(args)
    sum = 0
    for i in args:
        sum += i
    print('Sum: %d'%sum)
 
    print(name,age,sex,args,kwargs)
    for i in kwargs:
        print('%s: %s'%(i,kwargs[i]))
 
 
print_info('charon',22)   # 位置参数
print_info(age=21, name='alan')  # 关键字参数
print_info('charon',23, "female", 1,2,3,4,5,6,7,8)
print_info('charon',23, "female", 1,2,3,4,5,6,7,8, job="IT", height=180)
 

return返回值

函数里若没有return, 会默认返回一个None
如果return多个对象, 那么python会帮我把多个对象封装成一个元组
作用:
1.结束函数  2. 返回某个值
 

函数的作用域

L: local 局部作用域
E: enclosing  嵌套的父级函数的局部的作用域
G: global  全局变量
B: built-in  系统固定模块里面的变量
L>E>G>B  优先顺序
 
x = int(2.9)   #built-int
g_cnt = 0   #global
def outer():
    o_cnt = 2    #enclosing
    def inner():
        i_cnt = 3   #local
 

 global,nonlocal关键字

count = 10
def f():
    global count   
#若无此句, 下面的操作会出现错误,因为在局部作用域中不能操作全局变量, 若加了此句, 使其能够操作全局变量  同理还有关键词nonlocal用于父级函数中的变量
    count += 10
    print(count)
 

传参

def f(*args):
    print(args)
f(*[1,2,3])
 
 
def f1(**kwargs):
    print(kwargs)
f1(**{'name':'alan'})
 

高阶函数

1.函数名可以被赋给其他变量
def foo():
    print('foo')
bar=foo
bar()
foo()
print(id(foo),id(bar))  #4321123592 4321123592
2.函数名可以被定义在另一个函数内作为函数参数, 还可以作为函数返回值
def f2(n):
    return n**2
 
def f3(a,b,func):
    return func(a)+func(b)
 
print(f3(1,2,f2))
def outter():
    def inner():
        return 8
    return inner()
ret = outter
print(ret())  #ret若不加()则返回函数地址

 

递归函数

  1. 如果一个函数在内部调用自身本身,这个函数就是递归函数
  2. 有一个明确的结束条件
  3. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  4. 但凡是递归可以写的, 循环都可以解决
  5. 递归效率不高,递归层次过多会导致栈溢出
#阶乘
def fatc(n):
    if n == 1:
        return 1
    return n*fatc(n-1)
 
print(fatc(5))
 
#斐波那契数列
def fibo(n):
    if n <= 1:
        return n
    return fibo(n-1)+fibo(n-2)
 
print(fibo(8))

  

内置函数

内置函数进行了如下分类:
    数学运算(7个)
    类型转换(24个)
    序列操作(8个)
    对象操作(7个)
    反射操作(8个)
    变量操作(2个)
    交互操作(2个)
    文件操作(1个)
    编译执行(4个)
    装饰器(3个)
 

# 数学运算

abs:求数值的绝对值
>>> abs(-2)
2
divmod:返回两个数值的商和余数
>>> divmod(5,2)
(2, 1)
>> divmod(5.5,2)
(2.0, 1.5)
max:返回可迭代对象中的元素中的最大值或者所有参数的最大值
复制代码
>>> max(1,2,3) # 传入3个参数 取3个中较大者
3
>>> max('1234') # 传入1个可迭代对象,取其最大元素值
'4'
>>> max(-1,0) # 数值默认去数值较大者
0
>>> max(-1,0,key = abs) # 传入了求绝对值函数,则参数都会进行求绝对值后再取较大者
-1
复制代码
min:返回可迭代对象中的元素中的最小值或者所有参数的最小值
复制代码
>>> min(1,2,3) # 传入3个参数 取3个中较小者
1
>>> min('1234') # 传入1个可迭代对象,取其最小元素值
'1'
>>> min(-1,-2) # 数值默认去数值较小者
-2
>>> min(-1,-2,key = abs)  # 传入了求绝对值函数,则参数都会进行求绝对值后再取较小者
-1
复制代码
pow:返回两个数值的幂运算值或其与指定整数的模值
>>> pow(2,3)
>>> 2**3

>>> pow(2,3,5)
>>> pow(2,3)%5
round:对浮点数进行四舍五入求值
>>> round(1.1314926,1)
1.1
>>> round(1.1314926,5)
1.13149
sum:对元素类型是数值的可迭代对象中的每个元素求和
复制代码
# 传入可迭代对象
>>> sum((1,2,3,4))
10
# 元素类型必须是数值型
>>> sum((1.5,2.5,3.5,4.5))
12.0
>>> sum((1,2,3,4),-10)
0
复制代码
   

# 类型转换

 

bool:根据传入的参数的逻辑值创建一个新的布尔值
>>> bool() #未传入参数
False
>>> bool(0) #数值0、空序列等值为False
False
>>> bool(1)
True
int:根据传入的参数创建一个新的整数
>>> int() #不传入参数时,得到结果0。
0
>>> int(3)
3
>>> int(3.6)
3
float:根据传入的参数创建一个新的浮点数
>>> float() #不提供参数的时候,返回0.0
0.0
>>> float(3)
3.0
>>> float('3')
3.0
complex:根据传入参数创建一个新的复数
>>> complex() #当两个参数都不提供时,返回复数 0j。
0j
>>> complex('1+2j') #传入字符串创建复数
(1+2j)
>>> complex(1,2) #传入数值创建复数
(1+2j)
str:返回一个对象的字符串表现形式(给用户)
复制代码
>>> str()
''
>>> str(None)
'None'
>>> str('abc')
'abc'
>>> str(123)
'123'
复制代码
bytearray:根据传入的参数创建一个新的字节数组
>>> bytearray('中文','utf-8')
bytearray(b'\xe4\xb8\xad\xe6\x96\x87')
bytes:根据传入的参数创建一个新的不可变字节数组
>>> bytes('中文','utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
memoryview:根据传入的参数创建一个新的内存查看对象
>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>> v[-1]
103
ord:返回Unicode字符对应的整数
>>> ord('a')
97
chr:返回整数所对应的Unicode字符
>>> chr(97) #参数类型为整数
'a'
bin:将整数转换成2进制字符串
>>> bin(3) 
'0b11'
oct:将整数转化成8进制数字符串
>>> oct(10)
'0o12'
hex:将整数转换成16进制字符串
>>> hex(15)
'0xf'
tuple:根据传入的参数创建一个新的元组
>>> tuple() #不传入参数,创建空元组
()
>>> tuple('121') #传入可迭代对象。使用其元素创建新的元组
('1', '2', '1')
list:根据传入的参数创建一个新的列表
>>>list() # 不传入参数,创建空列表
[] 
>>> list('abcd') # 传入可迭代对象,使用其元素创建新的列表
['a', 'b', 'c', 'd']
dict:根据传入的参数创建一个新的字典
复制代码
>>> dict() # 不传入任何参数时,返回空字典。
{}
>>> dict(a = 1,b = 2) #  可以传入键值对创建字典。
{'b': 2, 'a': 1}
>>> dict(zip(['a','b'],[1,2])) # 可以传入映射函数创建字典。
{'b': 2, 'a': 1}
>>> dict((('a',1),('b',2))) # 可以传入可迭代对象创建字典。
{'b': 2, 'a': 1}
复制代码
set:根据传入的参数创建一个新的集合
>>>set() # 不传入参数,创建空集合
set()
>>> a = set(range(10)) # 传入可迭代对象,创建集合
>>> a
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
frozenset:根据传入的参数创建一个新的不可变集合
>>> a = frozenset(range(10))
>>> a
frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
enumerate:根据可迭代对象创建枚举对象
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) #指定起始值
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
range:根据传入的参数创建一个新的range对象
复制代码
>>> a = range(10)
>>> b = range(1,10)
>>> c = range(1,10,3)
>>> a,b,c # 分别输出a,b,c
(range(0, 10), range(1, 10), range(1, 10, 3))
>>> list(a),list(b),list(c) # 分别输出a,b,c的元素
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 4, 7])
>>>
复制代码
iter:根据传入的参数创建一个新的可迭代对象
复制代码
>>> a = iter('abcd') #字符串序列
>>> a
<str_iterator object at 0x03FB4FB0>
>>> next(a)
'a'
>>> next(a)
'b'
>>> next(a)
'c'
>>> next(a)
'd'
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    next(a)
StopIteration
复制代码
slice:根据传入的参数创建一个新的切片对象
复制代码
>>> c1 = slice(5) # 定义c1
>>> c1
slice(None, 5, None)
>>> c2 = slice(2,5) # 定义c2
>>> c2
slice(2, 5, None)
>>> c3 = slice(1,10,3) # 定义c3
>>> c3
slice(1, 10, 3)
复制代码
super:根据传入的参数创建一个新的子类和父类关系的代理对象
复制代码
#定义父类A
>>> class A(object):
    def __init__(self):
        print('A.__init__')

#定义子类B,继承A
>>> class B(A):
    def __init__(self):
        print('B.__init__')
        super().__init__()

#super调用父类方法
>>> b = B()
B.__init__
A.__init__
复制代码
object:创建一个新的object对象
>>> a = object()
>>> a.name = 'kim' # 不能设置属性
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    a.name = 'kim'
AttributeError: 'object' object has no attribute 'name'
 

 

# 序列操作

 

all:判断可迭代对象的每个元素是否都为True值
复制代码
>>> all([1,2]) #列表中每个元素逻辑值均为True,返回True
True
>>> all([0,1,2]) #列表中0的逻辑值为False,返回False
False
>>> all(()) #空元组
True
>>> all({}) #空字典
True
复制代码
any:判断可迭代对象的元素是否有为True值的元素
复制代码
>>> any([0,1,2]) #列表元素有一个为True,则返回True
True
>>> any([0,0]) #列表元素全部为False,则返回False
False
>>> any([]) #空列表
False
>>> any({}) #空字典
False
复制代码
filter:使用指定方法过滤可迭代对象的元素
复制代码
>>> a = list(range(1,10)) #定义序列
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def if_odd(x): #定义奇数判断函数
    return x%2==1

>>> list(filter(if_odd,a)) #筛选序列中的奇数
[1, 3, 5, 7, 9]
复制代码
map:使用指定方法去作用传入的每个可迭代对象的元素,生成新的可迭代对象
>>> a = map(ord,'abcd')
>>> a
<map object at 0x03994E50>
>>> list(a)
[97, 98, 99, 100]
next:返回可迭代对象中的下一个元素值
复制代码
>>> a = iter('abcd')
>>> next(a)
'a'
>>> next(a)
'b'
>>> next(a)
'c'
>>> next(a)
'd'
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    next(a)
StopIteration

#传入default参数后,如果可迭代对象还有元素没有返回,则依次返回其元素值,如果所有元素已经返回,则返回default指定的默认值而不抛出StopIteration 异常
>>> next(a,'e')
'e'
>>> next(a,'e')
'e'
复制代码
reversed:反转序列生成新的可迭代对象
>>> a = reversed(range(10)) # 传入range对象
>>> a # 类型变成迭代器
<range_iterator object at 0x035634E8>
>>> list(a)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
sorted:对可迭代对象进行排序,返回一个新的列表
复制代码
>>> a = ['a','b','d','c','B','A']
>>> a
['a', 'b', 'd', 'c', 'B', 'A']

>>> sorted(a) # 默认按字符ascii码排序
['A', 'B', 'a', 'b', 'c', 'd']

>>> sorted(a,key = str.lower) # 转换成小写后再排序,'a'和'A'值一样,'b'和'B'值一样
['a', 'A', 'b', 'B', 'c', 'd']
复制代码
zip:聚合传入的每个迭代器中相同位置的元素,返回一个新的元组类型迭代器
>>> x = [1,2,3] #长度3
>>> y = [4,5,6,7,8] #长度5
>>> list(zip(x,y)) # 取最小长度3
[(1, 4), (2, 5), (3, 6)]
 

# 对象操作

 

help:返回对象的帮助信息
复制代码
>>> help(str) 
Help on class str in module builtins:

class str(object)
 |  str(object='') -> str
 |  str(bytes_or_buffer[, encoding[, errors]]) -> str
 |  
 |  Create a new string object from the given object. If encoding or
 |  errors is specified, then the object must expose a data buffer
 |  that will be decoded using the given encoding and error handler.
 |  Otherwise, returns the result of object.__str__() (if defined)
 |  or repr(object).
 |  encoding defaults to sys.getdefaultencoding().
 |  errors defaults to 'strict'.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
  ***************************
复制代码
dir:返回对象或者当前作用域内的属性列表
复制代码
>>> import math
>>> math
<module 'math' (built-in)>
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
复制代码
id:返回对象的唯一标识符
>>> a = 'some text'
>>> id(a)
69228568
hash:获取对象的哈希值
>>> hash('good good study')
1032709256
type:返回对象的类型,或者根据传入的参数创建一个新的类型
复制代码
>>> type(1) # 返回对象的类型
<class 'int'>

#使用type函数创建类型D,含有属性InfoD
>>> D = type('D',(A,B),dict(InfoD='some thing defined in D'))
>>> d = D()
>>> d.InfoD
 'some thing defined in D'
复制代码
len:返回对象的长度
复制代码
>>> len('abcd') # 字符串
>>> len(bytes('abcd','utf-8')) # 字节数组
>>> len((1,2,3,4)) # 元组
>>> len([1,2,3,4]) # 列表
>>> len(range(1,5)) # range对象
>>> len({'a':1,'b':2,'c':3,'d':4}) # 字典
>>> len({'a','b','c','d'}) # 集合
>>> len(frozenset('abcd')) #不可变集合
复制代码
ascii:返回对象的可打印表字符串表现方式
复制代码
>>> ascii(1)
'1'
>>> ascii('&')
"'&'"
>>> ascii(9000000)
'9000000'
>>> ascii('中文') #非ascii字符
"'\\u4e2d\\u6587'"
复制代码
format:格式化显示值
复制代码
#字符串可以提供的参数 's' None
>>> format('some string','s')
'some string'
>>> format('some string')
'some string'

#整形数值可以提供的参数有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None
>>> format(3,'b') #转换成二进制
'11'
>>> format(97,'c') #转换unicode成字符
'a'
>>> format(11,'d') #转换成10进制
'11'
>>> format(11,'o') #转换成8进制
'13'
>>> format(11,'x') #转换成16进制 小写字母表示
'b'
>>> format(11,'X') #转换成16进制 大写字母表示
'B'
>>> format(11,'n') #和d一样
'11'
>>> format(11) #默认和d一样
'11'

#浮点数可以提供的参数有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None
>>> format(314159267,'e') #科学计数法,默认保留6位小数
'3.141593e+08'
>>> format(314159267,'0.2e') #科学计数法,指定保留2位小数
'3.14e+08'
>>> format(314159267,'0.2E') #科学计数法,指定保留2位小数,采用大写E表示
'3.14E+08'
>>> format(314159267,'f') #小数点计数法,默认保留6位小数
'314159267.000000'
>>> format(3.14159267000,'f') #小数点计数法,默认保留6位小数
'3.141593'
>>> format(3.14159267000,'0.8f') #小数点计数法,指定保留8位小数
'3.14159267'
>>> format(3.14159267000,'0.10f') #小数点计数法,指定保留10位小数
'3.1415926700'
>>> format(3.14e+1000000,'F')  #小数点计数法,无穷大转换成大小字母
'INF'

#g的格式化比较特殊,假设p为格式中指定的保留小数位数,先尝试采用科学计数法格式化,得到幂指数exp,如果-4<=exp<p,则采用小数计数法,并保留p-1-exp位小数,否则按小数计数法计数,并按p-1保留小数位数
>>> format(0.00003141566,'.1g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点
'3e-05'
>>> format(0.00003141566,'.2g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留1位小数点
'3.1e-05'
>>> format(0.00003141566,'.3g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留2位小数点
'3.14e-05'
>>> format(0.00003141566,'.3G') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点,E使用大写
'3.14E-05'
>>> format(3.1415926777,'.1g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留0位小数点
'3'
>>> format(3.1415926777,'.2g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留1位小数点
'3.1'
>>> format(3.1415926777,'.3g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留2位小数点
'3.14'
>>> format(0.00003141566,'.1n') #和g相同
'3e-05'
>>> format(0.00003141566,'.3n') #和g相同
'3.14e-05'
>>> format(0.00003141566) #和g相同
'3.141566e-05'
复制代码
vars:返回当前作用域内的局部变量和其值组成的字典,或者返回对象的属性列表
复制代码
#作用于类实例
>>> class A(object):
    pass

>>> a.__dict__
{}
>>> vars(a)
{}
>>> a.name = 'Kim'
>>> a.__dict__
{'name': 'Kim'}
>>> vars(a)
{'name': 'Kim'}
复制代码
 

# 反射操作

 

__import__:动态导入模块
index = __import__('index')
index.sayHello()
isinstance:判断对象是否是类或者类型元组中任意类元素的实例
>>> isinstance(1,int)
True
>>> isinstance(1,str)
False
>>> isinstance(1,(int,str))
True
issubclass:判断类是否是另外一个类或者类型元组中任意类元素的子类
复制代码
>>> issubclass(bool,int)
True
>>> issubclass(bool,str)
False

>>> issubclass(bool,(str,int))
True
复制代码
hasattr:检查对象是否含有属性
复制代码
#定义类A
>>> class Student:
    def __init__(self,name):
        self.name = name

        
>>> s = Student('Aim')
>>> hasattr(s,'name') #a含有name属性
True
>>> hasattr(s,'age') #a不含有age属性
False
复制代码
getattr:获取对象的属性值
复制代码
#定义类Student
>>> class Student:
    def __init__(self,name):
        self.name = name

>>> getattr(s,'name') #存在属性name
'Aim'

>>> getattr(s,'age',6) #不存在属性age,但提供了默认值,返回默认值

>>> getattr(s,'age') #不存在属性age,未提供默认值,调用报错
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    getattr(s,'age')
AttributeError: 'Stduent' object has no attribute 'age'
复制代码
setattr:设置对象的属性值
复制代码
>>> class Student:
    def __init__(self,name):
        self.name = name

        
>>> a = Student('Kim')
>>> a.name
'Kim'
>>> setattr(a,'name','Bob')
>>> a.name
'Bob'
复制代码
delattr:删除对象的属性
复制代码
#定义类A
>>> class A:
    def __init__(self,name):
        self.name = name
    def sayHello(self):
        print('hello',self.name)

#测试属性和方法
>>> a.name
'小麦'
>>> a.sayHello()
hello 小麦

#删除属性
>>> delattr(a,'name')
>>> a.name
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    a.name
AttributeError: 'A' object has no attribute 'name'
复制代码
callable:检测对象是否可被调用
复制代码
>>> class B: #定义类B
    def __call__(self):
        print('instances are callable now.')

        
>>> callable(B) #类B是可调用对象
True
>>> b = B() #调用类B
>>> callable(b) #实例b是可调用对象
True
>>> b() #调用实例b成功
instances are callable now.
复制代码
 

# 变量操作

 

globals:返回当前作用域内的全局变量和其值组成的字典
>>> globals()
{'__spec__': None, '__package__': None, '__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>}
>>> a = 1
>>> globals() #多了一个a
{'__spec__': None, '__package__': None, '__builtins__': <module 'builtins' (built-in)>, 'a': 1, '__name__': '__main__', '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>}
locals:返回当前作用域内的局部变量和其值组成的字典
复制代码
>>> def f():
    print('before define a ')
    print(locals()) #作用域内无变量
    a = 1
    print('after define a')
    print(locals()) #作用域内有一个a变量,值为1

    
>>> f
<function f at 0x03D40588>
>>> f()
before define a 
{} 
after define a
{'a': 1}
复制代码
 

# 交互操作

 

print:向标准输出对象打印输出
>>> print(1,2,3)
1 2 3
>>> print(1,2,3,sep = '+')
1+2+3
>>> print(1,2,3,sep = '+',end = '=?')
1+2+3=?
input:读取用户输入值
>>> s = input('please input your name:')
please input your name:Ain
>>> s
'Ain'
 

# 文件操作

 

open:使用指定的模式和编码打开文件,返回文件读写对象
# t为文本读写,b为二进制读写
>>> a = open('test.txt','rt')
>>> a.read()
'some text'
>>> a.close()
 

# 编译执行

 

compile:将字符串编译为代码或者AST对象,使之能够通过exec语句来执行或者eval进行求值
复制代码
>>> #流程语句使用exec
>>> code1 = 'for i in range(0,10): print (i)'
>>> compile1 = compile(code1,'','exec')
>>> exec (compile1)


>>> #简单求值表达式用eval
>>> code2 = '1 + 2 + 3 + 4'
>>> compile2 = compile(code2,'','eval')
>>> eval(compile2)
10
复制代码
eval:执行动态表达式求值
>>> eval('1+2+3+4')
10
exec:执行动态语句块
>>> exec('a=1+2') #执行语句
>>> a
3
repr:返回一个对象的字符串表现形式(给解释器)
>>> a = 'some text'
>>> str(a)
'some text'
>>> repr(a)
"'some text'"
 

# 装饰器

 

property:标示属性的装饰器
复制代码
>>> class C:
    def __init__(self):
        self._name = ''
    @property
    def name(self):
        """i'm the 'name' property."""
        return self._name
    @name.setter
    def name(self,value):
        if value is None:
            raise RuntimeError('name can not be None')
        else:
            self._name = value

            
>>> c = C()

>>> c.name # 访问属性
''
>>> c.name = None # 设置属性时进行验证
Traceback (most recent call last):
  File "<pyshell#84>", line 1, in <module>
    c.name = None
  File "<pyshell#81>", line 11, in name
    raise RuntimeError('name can not be None')
RuntimeError: name can not be None

>>> c.name = 'Kim' # 设置属性
>>> c.name # 访问属性
'Kim'

>>> del c.name # 删除属性,不提供deleter则不能删除
Traceback (most recent call last):
  File "<pyshell#87>", line 1, in <module>
    del c.name
AttributeError: can't delete attribute
>>> c.name
'Kim'
复制代码
classmethod:标示方法为类方法的装饰器
复制代码
>>> class C:
    @classmethod
    def f(cls,arg1):
        print(cls)
        print(arg1)

        
>>> C.f('类对象调用类方法')
<class '__main__.C'>
类对象调用类方法

>>> c = C()
>>> c.f('类实例对象调用类方法')
<class '__main__.C'>
类实例对象调用类方法
复制代码
staticmethod:标示方法为静态方法的装饰器
复制代码
# 使用装饰器定义静态方法
>>> class Student(object):
    def __init__(self,name):
        self.name = name
    @staticmethod
    def sayHello(lang):
        print(lang)
        if lang == 'en':
            print('Welcome!')
        else:
            print('你好!')

            
>>> Student.sayHello('en') #类调用,'en'传给了lang参数
en
Welcome!

>>> b = Student('Kim')
>>> b.sayHello('zh')  #类实例对象调用,'zh'传给了lang参数
zh
你好
View Code

几个重要内置函数

1. filter(function, sequence)
str = ['a', 'b', 'c', 'd']
def fun1(s):
    if s != 'a':
        return s
 
ret = filter(fun1, str)
print(ret)  #<filter object at 0x101e346a0>
print(list(ret))  # ret是一个迭代器对象 ['b','c','d'] 过滤掉a
 
2. map(function, sequence)
str = ['d', 'a', 'b']
def fun2(s):
    return s + "alan"
ret = map(fun2, str)
 
print(ret)  # map object的迭代器
print(list(ret))  # ['dalan', 'aalan', 'balan']



#sequence可以有多个
def add(x,y):
    return x+y
print (list(map(add, range(10), range(10))))
 
 
3. reduce(function, sequence, starting_value)
from functools import reduce
def add1(x, y):
    return x + y
 
print(reduce(add1, range(1, 101)))  # 5050 (注:1+2+...+100) range(1,101)是1到100的序列
print(reduce(add1, range(1, 101), 20))  # 5070 (注:1+2+...+100+20)
 
4. lambda (匿名函数): 用 lamdba 关键字标识, 冒号(:)左侧表示函数接收的参数(a,b), 冒号(:)右侧表示函数的返回值(a+b)
普通函数与匿名函数的对比:
# 普通函数
def add(a, b):
    return a + b
print(add(2, 3))
 
# 匿名函数
add = lambda a, b: a + b
print(add(2, 3))
 

命令式编程 VS 函数式编程

命令式编程即普通常用的面向对象编程, 有有变量(对应着存储单元), 赋值语句(获取, 存储指令), 表达式(内存引用和算术运算)和控制语句(跳转指令), 命令式编程关心解决问题的步骤
 
函数式编程
函数式编程关心数据的映射(映射为函数中一一对应的关系)
好处:
1.代码简洁易懂 2.无副作用
#Fine the sum of positive number
number = [2, -5, 9, -7, 2, 5, 4, -1, 0, -3, 8]
positive = list(filter(lambda x: x > 0, number))
average = reduce(lambda x, y: x + y, positive) / len(positive)
print(average)

#阶乘
from functools import reduce
print (reduce(lambda x,y: x*y, range(1,6)))

#squares
squares = map(lambda x : x*x ,range(9))
print (squares)#  <map object at 0x10115f7f0>迭代器
print (list(squares))#[0, 1, 4, 9, 16, 25, 36, 49, 64]

 

 

闭包

# 函数内部可以直接读取全局变量
n = 999
def f1():
    print(n)

f1()  # 999
# 函数外部无法读取函数内的局部变量
def f1():
    n = 999

print(n)  # NameError: name 'n' is not defined
# 从外部读取局部变量
def f1():
    n = 999
    def f2():
        print(n)
    return f2

ret = f1()
ret()  #999
# 这就是一个闭包
# 函数f2就被包括在函数f1内部, 这时f1内部的所有局部变量, 对f2都是可见的. 但是反过来就不行, f2内部的局部变量, 对f1就是不可见的. # 这就是"链式作用域"结构(chain scope),对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立. # f2可以读取f1中的局部变量, 那么只要把f2作为返回值, 这就就可以在f1外部读取它的内部变量.
闭包(closure)是函数式编程的重要的语法结构
定义:如果在一个内部函数里, 对在外部作用域(但不是在全局作用域)的变量进行引用, 那么内部函数就被认为是闭包(closure).

闭包就是能够读取其他函数内部变量的函数, 闭包简单理解成"定义在一个函数内部的函数".


# 关于闭包: 闭包=内部函数+定义函数时的环境,inner就是函数块,x就是环境
def outer():
    x=10
    def inner():   #条件一: inner是内部函数
        print(x)   #条件二: x是外部环境的一个变量且不是全局变量
 
    return inner   #结论: 内部函数inner就是一个闭包
 
#inner() #直接这样无法调用inner函数
#outer()()
in_f = outer()
in_f()
作用1: 当闭包执行完后,仍然能够保持住当前的运行环境. 如:如果你希望函数的每次执行结果,都是基于这个函数上次的运行结果
作用2: 闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行
 

装饰器

装饰器(decorator) : 装饰器本质上是一个函数, 其作用就是为已经存在的对象添加额外的功能
封闭开放原则:
在大型的程序中分不同模块, 每个模块有自己的函数, 若要在函数添加功能, 直接在源代码上添加, 一旦出错可能导致整个程序出错, 所以这是不允许的, 应该遵守封闭开放原则
封闭:已经实现的功能代码不允许被修改 但 开放:可以实现功能的扩展
 
简单装饰器
import time
 
def foo():
    print('foo1...')
    time.sleep(1)
 
def bar():
    print('bar1...')
    time.sleep(2)
 
def show_time(f):
    start = time.time()
    f()
    end = time.time()
    print('spend %s'%(end-start))
 
show_time(foo)
show_time(bar)
#这样能实现功能, 但调用方式已经从调用foo()改变到show_time(foo), 所以这是不行的
 
#将show_time修改为装饰器
def foo():
    print('foo2...')
    time.sleep(1)
 
def bar():
    print('bar2...')
    time.sleep(2)
 
def show_time1(f):   #f是外部环境变量
    def inner():
        start = time.time()
        f()   #调用外部环境变量
        end = time.time()
        print('spend %s'%(end-start))
 
    return inner   #执行show_time1(foo)拿到的是inner的内存地址
 
foo = show_time1(foo)  #通过这句话建立联系
foo()  #相当于执行inner函数
bar = show_time1(bar)
bar()  #相当于执行inner函数
 
#更好的写法
def show_time2(f):  # f是外部环境变量
    def inner():
        start = time.time()
        f()  # 调用外部环境变量
        end = time.time()
        print('spend %s' % (end - start))
 
    return inner
 
@show_time2  #这句话相当于foo = show_time1(foo)
def foo():
    print('foo3...')
    time.sleep(1)
foo()
 
 
@show_time2
def bar():
    print('bar3...')
    time.sleep(2)
bar()
 
带参数的被装饰的函数(功能函数加参数)
import time

def show_time3(f):  # f是外部环境变量
    def inner(*x, **y):
        start = time.time()
        f(*x, **y)  # 调用外部环境变量
        end = time.time()
        print('spend %s' % (end - start))
 
    return inner
 
@show_time3  #这句话相当于add = show_time1(add)
def add(*a, **b):
    sum = 0
    for i in a:
        sum += i
    print(sum)
    time.sleep(1)
add(1,2,3,4,5)

 

装饰器加参数

import time

def time_logger(flag=''):
    def show_time4(f):  # f是外部环境变量
        def inner():
            start = time.time()
            f()  # 调用外部环境变量
            end = time.time()
            print('spend %s' % (end - start))
 
            if flag == 'true':
                print('The operation has benn recorded.....')
 
        return inner
 
    return show_time4
 
@time_logger('true')  #这句话相当于@show_time1只是多提供了一个flag变量给内部函数
def foo():
    print('foo4...')
    time.sleep(1)
foo()
@time_logger('lalala')  #这句话相当于@show_time1只是多提供了一个flag变量给内部函数
def bar():
    print('foo4...')
    time.sleep(1)
bar()
 
多层装饰器
def makebold(fn):
    def wrapper():
        return "<b>" + fn() + "</b>"
 
    return wrapper
 
 
def makeitalic(fn):
    def wrapper():
        return "<i>" + fn() + "</i>"
 
    return wrapper
 
 
@makebold
@makeitalic
def hello():
    return "hello charon"
 
print(hello())

 

装饰器应用: 登入

 1 with open('tb','r') as f_tb, open('wc','r') as f_wc:
 2     li_tb = f_tb.readlines()
 3     user_tb = li_tb[0].strip()
 4     pas_tb = li_tb[1].strip()
 5 
 6     li_wc = f_wc.readlines()
 7     user_wc = li_wc[0].strip()
 8     pas_wc = li_wc[1].strip()
 9 
10 print(user_tb,pas_tb)   #charon 123
11 print(user_wc,pas_wc)    #alan 123
12 
13 
14 login_status = False
15 def login(auth_type):
16     def auth(func):
17         def inner():
18             global login_status
19             if login_status == False:
20                 if auth_type == 'tb':
21                     username = input('TB_Username: ')
22                     password = input('TB_Password: ')
23                     if user_tb == username and pas_tb == password:
24                         print('Welcome....')
25                         func()
26                         login_status = True
27                     else:
28                         print('Wrong username or password')
29                 elif auth_type == 'wc':
30                     username = input('WC_Username: ')
31                     password = input('WC_Password: ')
32                     if user_wc == username and pas_wc == password:
33                         print('Welcome....')
34                         func()
35                         login_status = True
36                     else:
37                         print('Wrong username or password')
38 
39         return inner
40     return auth
41 
42 @login('tb')
43 def home():
44     print('welcome to home page....')
45 @login('wc')
46 def finance():
47     print('welcome to finance page....')
48 @login('tb')
49 def book():
50     print('welcome to book page....')
51 
52 
53 menu = ['1.home', '2.finance', '3.book', '4.exit']
54 
55 while True:
56     for i in menu:
57         print(i)
58 
59     choice = input(">>>:").strip()
60     if choice == '1':
61         home()
62     elif choice == '2':
63         finance()
64     elif choice == '3':
65         book()
66     else:
67         break
View Code


列表生成式

a = [x*x for x in range(10)]  #先到后面的for循环取元素, 对取出来的元素逐次进行前面的操作, 然后依次放入列表
print(a)


def f(n):
    return n**3
b = [f(x) for x in range(10)]
print(b)

赋值小知识点
#t可以是元祖,列表 a,b = t两者的数量应该一致, 否则会报错
t = ('123', 8)
a,b = t
print(a,b)

 

生成器(generator): 

列表中每个元素都占据内存空间, 若创建一个列表而仅用几个元素就浪费了内存空间
在Python中,一边循环一边计算的机制,称为生成器:generator
生成器有两种创建方式和两个方法:
第一种方式: 将列表生成式的[]改成()    第1个方法: next() 生成器在创建的时候已经决定了能计算出值得个数, 一旦调用next的次数超过就会报错
s = (x*2 for x in range(3))
print(s)  #<generator object <genexpr> at 0x1041269e8>
print(next(s))  #0  等价于s.__next__()     In py2.x: s.next()
print(next(s))  #2
print(next(s))  #4
#print(next(s))  #报错:StopIteration

#生成器是一个可迭代对象(iterable): 拥有__iter__()方法的都可以称为可迭代对象如列表,元祖,字典,迭代器等
s1 = (x*2 for x in range(5))
for i in s1:
    print(i)
generator保存的是算法,每次调用next(s),就计算出s的下一个元素的值,直到计算到最后一个元素. 同时生成器是一个可迭代对象, 所以可以使用for循环

第二种方式:如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
def foo():
    print('ok1')
    yield 1   #相当于返回1
    print('ok2')
    yield 2
g = foo()
print(g)  #<generator object foo at 0x101e26a98>
foo()   #没执行, 它已经变成生成器对象

a = next(g)   #ok1
b = next(g)   #ok2
print(a)   #1
print(b)   #2

for i in foo():
    print(i)   # ok1 1 ok2 2
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现:
#斐波那契数列
def fib(max):
    n, before, after = 0, 0, 1
    while n < max:
        print(before)
        before, after = after, before+after
        n = n + 1

fib(8)

#通过生成器完成斐波那契数列
def fib1(max):
    n, before, after = 0, 0, 1
    while n < max:
        #print(before)
        yield before
        before, after = after, before+after
        n = n + 1
gg = fib1(8)
print(gg)  #<generator object fib1 at 0x104026af0>
print(next(gg))   # 0
print(next(gg))   # 1
print(next(gg))   # 1
print(next(gg))   # 2
generator函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

第2个方法: send方法和next()方法一样, 但是可以往函数传值
def bar():
    print('ok1')
    str = yield 1   #str = 'eee
    print(str)

    print('ok2')
    yield 2

b = bar()
y1 = b.send(None)  #ok1    等价于next(b)   第一次send前如果没有next, 只能传一个send(None)
print(y1)  #1
y2 = b.send('eee')  #ok2
print(y2)   #2

通过
生成器yield实现伪并发(伪同时进行)
import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer():
    c = consumer('A')
    c2 = consumer('B')  #生成两个生成器对象, 不是函数并无执行
    c.__next__()   #开始调用生成器
    c2.__next__()
    print("老子开始准备做包子啦!")
    for i in range(1,6):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)

producer()
通过生成器实现协程并行运算

 

迭代器(Iterator):

生成器都是迭代器, 但是迭代器不一定是生成器
迭代器满足两个条件: 1. 有iter()方法    2. 有next()方法
l = [1,2,3,5]
d = iter(l)
print(d)  #<list_iterator object at 0x101cb7240>

print(next(d))  #1
print(next(d))  #2
print(next(d))  #3
print(next(d))  #5
#print(next(d))  #StopIteration
for循环内部工作: 本质上就是通过不断调用next()函数实现的    
  1. 调用可迭代对象的iter方法, 返回一个迭代器对象
  2. 调用迭代器的next方法
  3. 处理StopIteration异常

可以使用isinstance()判断一个对象是否匹配:
from collections import Iterable,Iterator

print(isinstance([1,2],list))   #True
l = [1,2,3,5]
d = iter(l)
print(isinstance(l,list))       #True
print(isinstance(l,Iterable))   #True
print(isinstance(l,Iterator))   #False

凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型;
集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象 
 
 
 
 
posted @ 2018-01-10 10:46  Charonnnnn  阅读(204)  评论(0)    收藏  举报