Python 和 Lua 学习比较 三(下)

上面一遍文章讲了函数,但是没有讲完,要是一股脑都放在一片文章里,篇幅有点长,所以这里分成两部分。

下面继续讲python和lua中的函数概念。

函数多返回值的区别

python和lua函数提供了一种非常规的机制,但很方便,函数可以一次返回多个值。

python

def foo0():pass # 无返回
...
def foo1():return "a" # 返回1个
...
def foo2():return "a","b" # 返回2个
...

lua

function foo0 () end -- 无返回             
function foo1 () return 'a' end --返回1个   
function foo2 () return 'a','b' end--返回2个

看下面的例子,注意区分两者的不同之处:
lua lua的特性比较多,所以这一次把lua的示例提前。

x,y = foo2()     -- x='a', y='b'
x = foo2()       -- x='a','b'被舍弃
x,y,z = 10,foo2()-- x=10, y='a', z='b'
x,y = foo0()     -- x=nil, y=nil
x,y = foo1()     -- x='a', y=nil
x,y,z = foo2()   -- x='a', y='b', z=nil
print(foo2() .. "x")   --打印  ax  当函数调用出现在表达式中的时候,Lua只取了一个返回值用来做运算,所以只看到 ax

python

x,y = foo2()     # x='a', y='b'
x = foo2()       # x=('a', 'b') ,这里区别很大
x,y,z = 10,foo2()# 报错
x,y = foo0()     # 报错
x,y = foo1()     # 报错
x,y,z = foo2()   # 报错
print(foo2() .. "x")   #报错

仔细注意python和lua的区别!
其实python对多返回值只是把它们打包成tuple元组(只读),如果你要修改那么会报错:

>>> x[0] = "c"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

lua在这方面更胜一筹,各有各的特色嘛。

函数返回值也能构造一个对象
lua

a = {foo0()}     -- a = {}  (an empty table)
a = {foo1()}     -- a = {'a'}
a = {foo2()}     --[[ a = {'a', 'b'} 这种取到多个返回值的只能是foo2放在最后一个, 
如果像下面,foo2不是最后一个,那么只能取第一个返回值。
--]]
a = {foo0(), foo2(), 4}   -- a[1] = nil, a[2] = 'a', a[3] = 4

python

a = [foo0()]     # a = [None]  包含一个None类型的列表
a = [foo1()]     # a = ['a']
a = [foo2()]     # a = [('a', 'b')] ,这里区别很大
a = [foo0(), foo2(), 4]   # a[0] = None, a[1] = ('a','b'), a[2] = 4

我们还可以像下面这样定义lua函数~

function foo (i)
    if i == 0 then return foo0()
       elseif i == 1 then return foo1()
       elseif i == 2 then return foo2()
    end
end

 print(foo(1))     --> a
 print(foo(2))     --> a  b
 print(foo(0))     -- (no results)
 print(foo(3))     -- (no results)

--可以通过加括号的方式,强制只返回一个值。在python中则没什么卵用!
print((foo2()))        --> a

python

>>> def foo(i):
...     if i == 0 : return foo0()
...     elif i == 1 : return foo1()
...     elif i == 2 : return foo2()
...
>>>
>>>
>>> print(foo(1))
a
>>> print((foo(2))) # 加了括号,还是一样的输出
('a', 'b')
>>> print(foo(0))
None
>>> print(foo(3))
None

更多关于python函数特性

在讲python函数的更多之前,我们先看看python的Lambdas
它的语法是 lambda arguments : expression ,它能帮我们生成一个匿名函数对象,函数呢类似下面这样:

def <lambda>(arguments):
    return expression

知晓上面的语法后,我们就可以很简单的创造函数了。
python

>>> def make_incrementor(n): # 返回一个函数对象
...     return lambda x: x + n
...
>>> f = make_incrementor(42) # 这里指定 n = 42
>>> f(0) # 我们传入 x=0
42
>>> f(1) # 我们传入 x=1
43

python 函数参数注解,虽然python提供了动态类型变量,但是一般来说我们的函数只能处理固定类型的数据,不可能变来变去。所以有了这个东东:
python

>>> def f(ham: str, eggs: str = 'eggs') -> str:
...     print("Annotations:", f.__annotations__)#打印注解
...     print("Arguments:", ham, eggs)
...     return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'

在函数申明的时候,ham冒号后面指定了我的类型为str,egg也指定类型为str,并且给了默认参数'eggs', -> str 表示这个函数返回字符串。

更多关于lua函数特性

lua可变长参数

printResult = ""

function print (...) -- 三个点表示函数接受可变长参数
  for i,v in ipairs({...}) do -- 记得以前版本是可以直接用arg关键字的,但是现在只有这个{...},{...} 记录所有传入的参数,#{...}记录参数数量
    printResult = printResult .. tostring(v) .. "\t"
  end
  printResult = printResult .. "\n"
end

在讲固定参数和不定参数前先举个其他的例子:
大多数时候,我们都是用函数的第一个返回值的,但是有时候我们只用函数的第二个返回值类似:

local _, x = string.find(s, p)-- 只用第二个返回值 x

一个替代的方法是:

print(string.find("hello hello", " hel"))           -->6 9
print(select(1, string.find("hello hello", " hel")))-->6 9
-- 上面那个select,一开始用的时候让我吃惊,说好的取一个返回值的。。。
-- 不过大家记住就好了,上面select 1 其实没卵用。
print(select(2, string.find("hello hello", " hel")))--> 9

仔细观察select函数的参数,发现select就是这样一个函数,第一个固定参数,后面的不定。
类似的,我们可以申明这样的函数:function g (a, b, ...) end

调用g之后:

g(3)          实际参数: a=3, b=nil, {...}={}
g(3, 4)       实际参数: a=3, b=4, {...}={}
g(3, 4, 5, 8) 实际参数: a=3, b=4, {...}={5, 8}

上面例子的最好实践就是格式化输出

function fwrite (fmt, ...)
  return io.write(string.format(fmt, table.unpack({...})))--使用table.unpack直接解包所有参数
end

非全局lua函数,

Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end

等同于:

Lib = {
  foo = function (x,y) return x + y end,
  goo = function (x,y) return x - y end
}

还有另一种相同结果的语法:

Lib = {}
function Lib.foo (x,y)
  return x + y
end
function Lib.goo (x,y)
  return x - y
end

申明局部函数(非代码语言)

local f = function (...)
  ...
end

local g = function (...)
  ...
  f()   -- external local `f' is visible here
  ...
end

--另一种申明方法:
local function f (...)
  ...
end

在使用local关键字的时候需要注意递归写法。

local fact = function (n)
  if n == 0 then return 1
  else return n*fact(n-1) --这里报错,因为我们的fact这时候还是未定义的
  end
end

-- 修复方法一
local fact -- 提前定义
fact = function (n)
     if n == 0 then return 1
     else return n*fact(n-1) -- 递归调用
     end
end
-- 修复方法二
local function fact (n)
     if n == 0 then return 1
     else return n*fact(n-1)
     end
end


-- 下面的例子,必须先申明f,g
local f, g    -- 提前申明

function g ()
  ...  f() ... --相互调用
end

function f ()
  ...  g() ... --相互调用
end

写lua函数的时候尽量使用 Tail Call:
lua

function f (x) -- 最简单的tail call例子
    return g(x)--f调用g之后,不需要做任何事,这样就不需要保留g的返回信息在当前函数(f)栈中,类似这样的调用我们说它们支持tail calls,就像lua解释器一样
end

写在函数最后的话:

代码风格

  1. 使用4个空格缩进,而非tab
  2. 一行不要超过79个字符
  3. 函数和类(以后会介绍)的上下行空开
  4. 尽量多的写代码注释
  5. 使用文档字符串,仅python
  6. 操作符前后空格,逗号后空格
  7. 保持命名一致。类(后面会介绍)命名:CamelCase,函数方法命名:lower_case_with_underscores
  8. 使用UTF8编码
  9. 不要使用ASCII以外的表情符号。

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值