在调用时计算默认值,Python入门笔记02

当def函数参数默认值为对象时,例如列表[],字典{}

二、函数

python 在调用时计算默认值

大家都知道python的默认值是在函数定义时计算出来的,
也就是说默认值只会计算一次, 之后函数调用时, 如果参数没有给出,

同一个值会赋值给变量, 这会导致, 如果我们想要一个list默认值,
新手通常这么写:

 

def foo(a=[]):

 a.append(3)

 print a

其实是错误的,两次调用会这样的结果:

 

[3]

[3, 3]

其实应该这么写

 

def baz(a=None):

   a = a or []

    a.append(3)

    print a

两次调用输出以下结果:

 

[3]

[3]

 

 

 

 

这样好挫啊, 搞的虽然有默认值用法,但是我们却需要写的和js,lua一样,
我们不能像c++一样, 在函数运行时每次执行默认值么.

用decorator可以模拟下

 

复制代码

import functools

import copy

def compute_default_value_for_each_call(func):

    defaults = func.__defaults__

    if not defaults:

        return None

    defaults = tuple(copy.copy(x) for x in defaults)

 

    @functools.wraps(func)

    def wrapper(*args, **kwargs):

        if func.__defaults__ != defaults:

            func.__defaults__ = tuple(copy.copy(y) for y in
defaults)

        return func(*args, **kwargs)

 

    return wrapper

 

 

@compute_default_value_for_each_call

def foo(b, a=[]):

    if b:

        a.append(3)

在调用时计算默认值,Python入门笔记02。    return a

韦德国际官网1946, 

import timeit

复制代码

这样两次调用foo(1), 结果为:

 

[3]

[3]

这个decorator有对未修改默认参数值做优化,
在我们不对默认值修改的情况下(比如打印变量a的内容), 性能有很大提升:

 

复制代码

@compute_default_value_for_each_call

def foo(b, a=[]):

    if b:

        a.append(3)

    return a

 

 

def foo2(b, a=None):

    a = a or []

    if b:

        a.append(3)

    return a

 

import timeit

 

print timeit.timeit(‘foo(1)’, setup=’from __main__ import foo’)

print timeit.timeit(‘foo(0)’, setup=’from __main__ import foo’)

print timeit.timeit(‘foo2(1)’, setup=’from __main__ import foo2′)

print timeit.timeit(‘foo2(0)’, setup=’from __main__ import foo2′)

复制代码

执行结果(调用1000000次的总时间)

 

4.32704997063

0.630109071732

0.445858955383

0.26370882988

性能上还过得去….

在调用时计算默认值
大家都知道python的默认值是在函数定义时计算出来的,
也就是说默认值只会计算一次, 之后函数调用时, 如果参数…

 

 

示例1:猜测一下,会输出什么??? 

2.1、重新认识函数

def ddd(a,b=[]):
    b.append(a)
    return b

print(ddd(1))
print(ddd(2,['a','b','c']))
print(ddd(3))

韦德国际官网1946 1

 

     Python
中所谓的使用函数,就是把你要处理的对象放到一个名字后面的括号里。简单来说,函数就是这么使用的,往里面塞东西就可以得到处理结果。

[1] 
[‘a’,’b’,’c’,’2′] [3]   ?????你是否认为是这样? 输出一下看看

 

输出结果:

– Python 的 内建函数(Built-in Functions)

D:Python27python.exe D:/untitled1/temp5.py
[1]
['a', 'b', 'c', 2]
[1, 3]

 

 

以 Python 3.60 版本为例,一共存在 68 个这样的函数,它们被统称为
内建函数(Built-in Functions)。

看到以上结果有什么想法,为什么呢???[1,
3]而不是[3],那么修改一下代码,输出b变量的内存地址看一下。我想,可以找到我要的答案

之所以被称为内建函数,并不是因为还有“外建函数”这个概念,“内建”的意思是在
Python 3.60 版本安装完成后,你无须创建就可以直接使用这些函数,即
表示这些函数是“自带”的而已。

def ddd(a,b=[]):
    b.append(a)
    print(id(b)) #查看内存地址
    return b

print(ddd(1))
print(ddd(2,['a','b','c']))
print(ddd(3))

 

输出结果:

Python 3.60 的 68个 内建函数(Built-in Functions):

D:Python27python.exe D:/untitled1/temp5.py
170580872
[1]
171586568
['a', 'b', 'c', 2]
170580872
[1, 3]
    Built-in Functions    
abs() dict() help() min() setattr()
all() dir() hex() next() slice()
any() divmod() id() object() sorted()
ascii() enumerate() input() oct() staticmethod()
bin() eval() int() open() str()
bool() exec() isinstance() ord() sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()  
delattr() hash() memoryview() set()  

从输出中,可以看出,除了,第二个print,其它两个内存是一们的。那么考虑一下为什么第二个为被改变。结果显而易见,因为第二个print改变了,b对象,重新创建了一个对象。

 

 

 

那么如果不想出现,每次调用,默认值对象不变的问题,可以这样改一下:

2.2、创建函数

def ddd(a,b=None):
    if type(b).__name__!='list':
        b = []

    b.append(a)
    print(id(b)) #查看内存地址
    return b

print(ddd(1))
print(ddd(2,['a','b','c']))
print(ddd(3))

 

初始值设置为None,通过类型判断来,进行内处理

– Python 创建函数的格式如下:

 

 

小结:

韦德国际官网1946 2

      
1.python定义def的时候,如果参数做为对象,那么,如果没有改变这个对象的前提下,那么即使,多次调用该函数也,不会创建新的对象。

 

         
那么就会出现多次调用函数,有可能都进行了处理。

 

  2.如果,没有特殊需求,函数参数,尽量不采用对象,如果一有需要,对象进行内处理。传默认值None

★ 重 点:

 

  ① def(即 define
,定义)的含义是创建函数,也就是定义一个函数。

  ② 闭合括号后面的 冒号( )必不可少。

  ③ 函数「缩进」后面的语句被称作
语句块(block),缩进是为了表明语句和逻辑的从属关系,是 Python
最显著的特征之一。(大部分语言会用大括号 { } 来表明这样从属关系)

  ④ return 即返回结果。在 Python 中 return 是可选的,如果没有 return
即函数的返回值为 ‘None’。 

 

☆ 注意:

  ① def 和 return 是 关键字(keyword),Python
就是靠识别这些特定的关键字来明白用户的意图,实现更为复杂的编程。

  ② 在 Python 中 return 是可选的(optional),这意味着你在创建函数时不写 return 也可以顺利地定义一个函数并调用,只不过
返回值 是 ‘None’ 罢了。

  ③ 我们把 使用函数 这种行为叫做“调用”(call)。即 调用函数 。

 

韦德国际官网1946 3

 

# 例子,温度的单位有 摄氏度 和 华氏度
,已知 摄氏度 与 华氏度 的转化公式为:F = 9/5*C+32 。

# 现在我们创建一个能实现 摄氏度 转化为
华氏度 的函数,并调用该函数实现转化:

 

def temp_converter(c):

return str(9/5*c+32) + ‘?F’

 

c_in = input(‘请输入摄氏温度:’)

c_in = int(c_in)

f = temp_converter(c_in)

print(‘华氏温度为:’ + f)

 

 

2.3、传递参数与参数类型

 

– 位置参数 与 关键词参数

 

    根据不同传递参数的方式,可以分为:位置参数 (positional argument)
与 关键词参数 (keyword argument)。

 

    在 调用函数 时,根据 该函数被创建时
各参数所在的位置顺序,分别把参数的值按顺序填到对应的位置,这样种传入参数的方式被称作「位置参数 (positional
argument)」。

 

    在 调用函数
时,在每个参数名称后面赋予一个我们想要传入的值。这种以名称作为一一对应的参数传入方式被称作「关键词参数 (keyword
argument)」。

 

韦德国际官网1946 4

 

# 例子,我们已知 梯形面积的计算公式为:S =
(a+b)*h/2

# 创建一个函数,计算梯形面积:

 

def tra_area(a,b,h):

return 1/2 * (a + b) * h

 

print(tra_area(h=3,b=2,a=1)) #
-成功,输出:4.5

print(tra_area(h=3,b=2,1)) #
-失败!原因:「位置参数」不能在「关键词参数」之后出现!

print(tra_area(a=1,b=2,3)) # 
-失败!原因:「位置参数」不能在「关键词参数」之后出现!

print(tra_area(1,2,h=3)) #
-成功,输出:4.5

print(tra_area(1,2,b=3)) #
-失败!原因:同一个参数不能被重复赋值!

 

☆ 注意:

    ①「关键词参数」可以不考虑位置顺序。

    ②「位置参数」不能在「关键词参数」之后出现!

    ③ 同一个参数不能被重复赋值!

 

#
我们现在给一组变量赋值,然后再调用函数,大家来看结果会有什么变化:

 

a = 1

b = 2

h = 3

print(tra_area(h,b,a)) # 输出:2.5

print(tra_area(h = h,b = b,a = a)) #
输出:4.5

 

☆ 注意:

    在 创建函数 时 设定的参数是「形参」,在 调用函数 时
填入的参数是「实参」,大家要搞清楚这两个概念。

 

– 默 认 参 数

 

    默认参数 就是
函数中某个有默认值的参数。调用函数时就算不给予填入参数,该函数仍然能照常运行。

 

  参数的默认值可以被更改,即 默认参数可以被重新赋值。

 

   
给一个参数设定默认值(创建默认参数)非常简单,我们只需要在定义参数的时候给参数赋值即可。如下:

 

def tra_area(a,b,h=3):

return 1/2 * (a + b) * h

 

print(tra_area(1,2)) # 输出:4.5

print(tra_area(1,2,6)) # 给默认参数重新赋值 6,输出:9.0

print(tra_area(1,2,h=6)) # 给默认参数重新赋值 6,输出:9.0

 

 ☆ print()函数的默认参数
sep(用于设定多个打印结果之间的分隔符号)的默认值为‘
’空格,但是我们可以将其重新设定为‘/n’ 即 换行
。也就是说将每个打印结果以换行符号进行分割。如下:

 

print(‘  *’,’ ***’,’*****’,’  |’,sep=’n’)

”””””””””””””””””’

以上代码输出:

  *

 ***

*****

  |

”””””””””””””””””’

 

 

2.4、设计自己的函数

 

  * 如果你现在困惑 函数 和 方法
到底是什么关系的话,为了顺利地往后进行,我可以告诉你 方法 就是 函数
的一种,只不过在不同的位置而已,使用原理和函数非常相似。

 

# 创建 file_create()
函数,作用:创建文件(尤其是.py文件)

# 该函数共有4个参数:

# namn -文件名

# content -文件内容

# extension -文件扩展名,即 后缀

# path -文件坐在的目录路径

def file_create(name,content,extension=’py’,path=’E:/PY_Test/New/’):

full_path = path + name + ‘.’ + extension

file = open(full_path,’w’)

file.write(content)

file.close()

print(‘文件 ‘ + name + ‘.’ + extension + ‘ 已被创建在 ‘ + path + ‘
中。’)

 

file_create(‘test’,’# hello world’) #
调用函数

 

 

# 创建 word_filter()
函数,作用:单词过滤器

# 该函数共有3个参数:

# content -内容

# target_word -要被过滤的单词

# new_word – 替换的单词

# 执行成功 返回
被过滤后的内容(str类型)。

def word_filter(content,target_word=’lame’,new_word=’Awesome’):

return content.replace(target_word,new_word)

 

new_content = word_filter(‘Python is lame! is very lame!! is very very
lame!!!’) # 调用函数

print(new_content)

# 输出:Python is Awesome! is very
Awesome!! is very very Awesome!!!

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注