Python 和 Lua 学习比较 三(上)
2016-09-14 15:40
477 查看
随着我们学习的深入,我们知道的更多了~~
今天来学习一下两者的Function(函数),函数是各种语言的核心部分,有了函数,我们可以写很简单的代码完成复杂的工作~。
比如我们常用的print,它就是一个函数,至于它怎么实现打印到屏幕的,我们并不知道,可能很复杂,但是我们只需要一句print(xx),就完成了打印。
lua
在lua函数中,你可以添加注释,但是没有像python的
在lua中还有个规则,不过不常用,那就是如果函数只有一个参数,并且参数是string或者是table的构造,那么圆括号可省略。
以上函数的调用效果相等。
lua 还提供了 面向对象式的函数访问:
o:foo(x) 等价于 o.foo(o, x)
类似的:
python
上述python函数,我们可以有三种方式调用:
默认参数是在函数定义的时候计算过的,所以
上面的代码将会输出5。
也因为只默认参数只执行一次,那么我们在赋值可变对象是会有其他问题。
如果不想每次函数调用共享这个默认参数,那么我们可以这样写:
lua
lua函数存在默认值,那就是nil,但是这个默认值是只读的,我们不能更改它,不能像python那样指定其他的值,下面会有一种替代的方法给我们的lua函数参数赋个默认值。
假设有上面的函数f;
调用
f(3) 实际参数: a=3, b=nil
f(3, 4) 实际参数: a=3, b=4
f(3, 4, 5) 实际参数: a=3, b=4 (5 is discarded)
由于参数为nil会导致程序崩溃,lua提供了类似默认参数的概念:
再回来看python:
python为函数还提供关键字参数。上面代码已有实例:
在python中,对函数参数做了更进一步的区分,所有参数分为位置参数和关键字参数(lua中只有位置参数,后面会介绍个替代方法)。
关键字参数 使用
上面这个函数接受一个必须参数(voltage),和三个可选参数(state, action, type);我们可以像下面这样调用这个函数:
下面的调用都是非法的:
通过以上的例子,我们大概了解到,python的函数:关键字参数必须跟在非关键字参数后面,不能出现没有定义的关键字,关键字参数之间的顺序可以随意替换,但不能对同一个参数指定多个值。对没有定义默认参数的参数需要给一个值。
lua中关键字参数的替换方法
在lua中传参数都是位置参数,如果想要类似python的关键字参数,需要自己定义:
我们调用的时候可以
前面说过,参数只有一个且是字符串或者table构造时,可以省略括号,不过最好还是加上括号,容易理解。
再回来说python
在python函数定义中,还有
可能你对上面的解释有点疑惑,我们来看具体的例子吧:
上面是我定义的一个函数,我们看看它的一个调用结果:
我来分析下,在上述的函数调用中,
arguments 获取的值是(“It’s very runny, sir.”,”It’s really very, VERY runny, sir.”)
keywords 获取的值是{‘shopkeeper’:”Michael Palin”,’client’:”Michael Palin”,’sketch’:”Cheese Shop Sketch”}
跟打印顺序不一样是因为函数中做了排序。
如果我们想在python中定义可变参数列表,那么我们可以这样申明函数:
还有,在我们的可变参数后面只能是用关键字参数的传参方式!
python
lua
未完待续。。。
今天来学习一下两者的Function(函数),函数是各种语言的核心部分,有了函数,我们可以写很简单的代码完成复杂的工作~。
比如我们常用的print,它就是一个函数,至于它怎么实现打印到屏幕的,我们并不知道,可能很复杂,但是我们只需要一句print(xx),就完成了打印。
函数定义
python>>> def fib(n): # 使用def定义fib函数,一个参数,输出斐波切纳数列;注意冒号 ... """Print a Fibonacci series up to n.""" #函数说明文档,函数体第一行字符串都会被当成说明文档。 ... a,b = 0,1 ''' 在函数体内,会生成一个新的标示表用于存储函数内的局部变量 也就是说函数闭包内,申明的变量是局部变量, 不能再这修改全局变量,除非申明global关键字 变量查找是顺序是局部标示表->函数闭包表->全局表->built-in names 函数的实参n也是函数体内的局部变量。传参方式:python统一地址传递, 以对象的引用方式,不是对象的值。 当函数体内调用其他函数时,会生成一个新的局部标示表,给新函数体使用。 函数一旦申明成功,函数名会被解释器标记成 user-defined function, 我们可以把它赋值给其他变量,就像起别名一样。 ''' ... while a < n: ... print(a,end=" ") ... a,b = b,a+b ... print() # 输出换行符 >>> fib(3) # 调用fib函数,我们传入参数3 0 1 1 2 >>> fib <function fib at 0x000000000275CAE8> >>> type(fib) # fib 是函数类型 <class 'function'> >>> fib.__doc__ #输出我们的函数说明 'Print a Fibonacci series up to n.' ''' python是通过 def 关键字来定义函数的, 后面跟函数名和参数列表(可空),再加冒号,函数体需要缩进 ''' >>> fib(0) #函数可以有返回值,如果没有明确的定义,默认返回None(内建类型) >>> print(fib(0)) # 通过 print 我们可以看到 None >>> type(fib2(0)) <class 'NoneType'> >>> # 下面让我们尝试返回这个数列,而不是只是打印它 >>> def fib2(n): # 返回数列 ... """Return a list containing the Fibonacci series up to n.""" ... result = [] # 定义空的结果存储 ... a, b = 0, 1 ... while a < n: ... result.append(a) #添加数据,比 result=result+[a] 更高效 ... a, b = b, a+b ... return result # 返回这个数据 ... >>> f100 = fib2(100) # 调用它 >>> f100 # 看输出的结果 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> def add(a): --计算a的每个数相加的和 ... sum = 0 ... for i in range(len(a)): ... sum = sum + a[i] ... return sum ... >>> sum = add([1,2,3,4,5]) >>> sum 15 >>>
lua
> function fib(n) -- 使用function定义fib函数 >> local a,b = 0,1 -- 指定a,b为局部变量 --[[ local指定是局部变量,跟python相反, 如果不指定local那么默认是全局变量。 --]] >> while a<n do -- 循环 >> print(a) -- 打印 >> a,b=b,a+b >> end >> end > fib(3) 0 1 1 2 > a = fib(0)--不同于python,lua默认返回的是nil > type(a)-- 直接type(fib(0))会报错 nil > function fib2(n) >> local result = {} >> local a,b = 0,1 >> while a<n do >> table.insert(result,a)--添加数据 >> a,b = b,a+b >> end >> return result -- 返回结果 >> end > fib2(3) table: 0053ae30 > for k,v in pairs(fib2(3)) do print(k,v) end 1 0 2 1 3 1 4 2 > function add (a) --计算table a每个数相加的和 >> local sum = 0 >> for i,v in ipairs(a) do #这里使用ipairs >> sum = sum + v >> end >> return sum >>end > > sum = add({1,2,3,4,5}) > sum 15
在lua函数中,你可以添加注释,但是没有像python的
__doc__可供查询函数说明。
在lua中还有个规则,不过不常用,那就是如果函数只有一个参数,并且参数是string或者是table的构造,那么圆括号可省略。
print "Hello World" <--> print("Hello World") dofile 'a.lua' <--> dofile ('a.lua') print [[a multi-linemessage]] <-->print([[a multi-linemessage]]) f{x=10, y=20} <--> f({x=10, y=20}) type{} <--> type({})
以上函数的调用效果相等。
lua 还提供了 面向对象式的函数访问:
o:foo(x) 等价于 o.foo(o, x)
函数默认参数
在c++中,每个函数的参数可以为其指定默认参数,然后有时候就可以不用传参数了,当然有默认值的参数必须跟着没有默认值的参数后面。类似的:
python
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = input(prompt) if ok in ('y', 'ye', 'yes'):#in 代表是否与其中一个相同 return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise OSError('uncooperative user') print(complaint)
上述python函数,我们可以有三种方式调用:
ask_ok('Do you really want to quit?')
ask_ok('OK to overwrite the file?', 2)
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
默认参数是在函数定义的时候计算过的,所以
i = 5 def f(arg=i): print(arg) i = 6 f()
上面的代码将会输出5。
也因为只默认参数只执行一次,那么我们在赋值可变对象是会有其他问题。
def f(a, L=[]): L.append(a) return L print(f(1)) # [1] print(f(2)) # [1,2] , 这里并不是我们想要的 [2] print(f(3)) # [1,2,3]
如果不想每次函数调用共享这个默认参数,那么我们可以这样写:
def f(a, L=None): if L is None: L = [] # 这样,每次函数调用都是生成新的对象 L.append(a) return L
lua
lua函数存在默认值,那就是nil,但是这个默认值是只读的,我们不能更改它,不能像python那样指定其他的值,下面会有一种替代的方法给我们的lua函数参数赋个默认值。
function f(a, b) return a or b end
假设有上面的函数f;
调用
f(3) 实际参数: a=3, b=nil
f(3, 4) 实际参数: a=3, b=4
f(3, 4, 5) 实际参数: a=3, b=4 (5 is discarded)
由于参数为nil会导致程序崩溃,lua提供了类似默认参数的概念:
count = 0 function incCount (n) n = n or 1 -- 这里对n初始化。如果为nil,赋值1,类似默认值 count = count + n end
再回来看python:
python为函数还提供关键字参数。上面代码已有实例:
print(a,end=" "),这里面的
end就是关键字参数。
在python中,对函数参数做了更进一步的区分,所有参数分为位置参数和关键字参数(lua中只有位置参数,后面会介绍个替代方法)。
关键字参数 使用
kwarg=value
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ') print("if you put", voltage, "volts through it.") print("-- Lovely plumage, the", type) print("-- It's", state, "!")
上面这个函数接受一个必须参数(voltage),和三个可选参数(state, action, type);我们可以像下面这样调用这个函数:
parrot(1000) # 1 位置参数 parrot(voltage=1000) # 1 keyword argument parrot(voltage=1000000, action='VOOOOOM') # 2 关键字参数 parrot(action='VOOOOOM', voltage=1000000) # 2 关键字参数 parrot('a million', 'bereft of life', 'jump') # 3 位置参数 parrot('a thousand', state='pushing up the daisies') # 1 位置, 1 关键字
下面的调用都是非法的:
parrot() # 必须参数丢失 voltage parrot(voltage=5.0, 'dead') # 非关键字参数在关键字参数后面 parrot(110, voltage=220) # 两个值给了同一个参数 parrot(actor='John Cleese') # 未知的关键字参数
通过以上的例子,我们大概了解到,python的函数:关键字参数必须跟在非关键字参数后面,不能出现没有定义的关键字,关键字参数之间的顺序可以随意替换,但不能对同一个参数指定多个值。对没有定义默认参数的参数需要给一个值。
>>> f(0,a=0) #给同一个参数赋值 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: f() got multiple values for argument 'a' >>> def f(a=0,b): #有默认值的在没默认值的前面 ... print(a,b) ... File "<stdin>", line 1 SyntaxError: non-default argument follows default argument
lua中关键字参数的替换方法
在lua中传参数都是位置参数,如果想要类似python的关键字参数,需要自己定义:
function rename (arg) return os.rename(arg.old, arg.new)#给文件改名字 end
我们调用的时候可以
rename {old="temp.lua", new="temp1.lua"}
前面说过,参数只有一个且是字符串或者table构造时,可以省略括号,不过最好还是加上括号,容易理解。
再回来说python
在python函数定义中,还有
*name和
**name的写法,前者表示一个tuple(元组)参数,接受所有超出参数列表的位置参数;后者表示一个dict(字典)参数,接受所有的关键字参数。在函数定义的时候,元组参数必须写在字典参数前面。
可能你对上面的解释有点疑惑,我们来看具体的例子吧:
def cheeseshop(kind, *arguments, **keywords): print("-- Do you have any", kind, "?") print("-- I'm sorry, we're all out of", kind) for arg in arguments: print(arg) print("-" * 40) keys = sorted(keywords.keys()) for kw in keys: print(kw, ":", keywords[kw])
上面是我定义的一个函数,我们看看它的一个调用结果:
>>> cheeseshop("Limburger", "It's very runny, sir.", ... "It's really very, VERY runny, sir.", ... shopkeeper="Michael Palin", ... client="John Cleese", ... sketch="Cheese Shop Sketch") -- Do you have any Limburger ? -- I'm sorry, w b64f e're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch
我来分析下,在上述的函数调用中,
arguments 获取的值是(“It’s very runny, sir.”,”It’s really very, VERY runny, sir.”)
keywords 获取的值是{‘shopkeeper’:”Michael Palin”,’client’:”Michael Palin”,’sketch’:”Cheese Shop Sketch”}
跟打印顺序不一样是因为函数中做了排序。
如果我们想在python中定义可变参数列表,那么我们可以这样申明函数:
def write_multiple_items(file, separator, *args): file.write(separator.join(args))
还有,在我们的可变参数后面只能是用关键字参数的传参方式!
>>> def concat(*args, sep="/"): ... return sep.join(args) ... >>> concat("earth", "mars", "venus") 'earth/mars/venus' >>> concat("earth", "mars", "venus", sep=".") 'earth.mars.venus' >>> def f(*args,a): ... pass ... >>> f(1,2,3) #这里的值无法传递到参数a,所以报错了 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: f() missing 1 required keyword-only argument: 'a'
参数解包
有时候为了方便,我们可能先把函数的参数打包起来,然后传给函数,这个时候直接调用函数当然会报错,我们需要解包它:python
# 解包队列 使用 * >>> list(range(3, 6)) # 普通调用 [3, 4, 5] >>> args = [3, 6] >>> list(range(*args)) # 解包list 参数调用 [3, 4, 5] # 解包字典 使用 ** >>> def parrot(voltage, state='a stiff', action='voom'): ... print("-- This parrot wouldn't", action, end=' ') ... print("if you put", voltage, "volts through it.", end=' ') ... print("E's", state, "!") ... >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} >>> parrot(**d) ## 使用操作符 ** 解包字典 -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
lua
-- 使用`table.unpack`解包table。记住lua中没有单独列表的概念,都是table实现的。 print(table.unpack{10,20,30}) --> 10 20 30 a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded f = string.find --这里把 string.find函数赋值给f,后面还要讲。 a = {"hello", "ll"} f(table.unpack(a)) -- 等价于 string.find("hello", "ll"),解包参数,给函数 -- 注: 在lua以前的版本是可以直接使用unpack的,但是我用的这个版本unpack已经放到table里面了。
未完待续。。。
相关文章推荐
- Python动态类型的学习---引用的理解
- Python3写爬虫(四)多线程实现数据爬取
- 垃圾邮件过滤器 python简单实现
- 下载并遍历 names.txt 文件,输出长度最长的回文人名。
- install and upgrade scrapy
- Scrapy的架构介绍
- Centos6 编译安装Python
- 使用Python生成Excel格式的图片
- 让Python文件也可以当bat文件运行
- [Python]推算数独
- Python中zip()函数用法举例
- Python中map()函数浅析
- Python将excel导入到mysql中
- Python在CAM软件Genesis2000中的应用
- 使用Shiboken为C++和Qt库创建Python绑定
- FREEBASIC 编译可被python调用的dll函数示例
- Python 七步捉虫法