python和ruby:一些需要注意的小区别。

寻技术 Python编程 / Ruby编程 2023年07月11日 133

 


 

基础区别

 

运算符号/和//

ruby只有/符号。它根据操作的数字类型返回对应的结果。如果数字的类型是int,则返回整除结构,如果是float,则返回float类型的计算结果。

python不一样。/符号,返回的是float类型的计算结果。//返回的是整除的结果。

 

变量声明

ruby不支持中文的变量声明。

python因为完全使用Unicode编码,所以可以使用中文字符作为变量名字。

 

关键字

True, False, None是Python的关键字,

true, false, nil是ruby的关键字。

含义都一样。

>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

 

 

字符串替换

python,可以使用format()方法替换字符串中{0}, {1}...的占位符号:

>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'

也可以使用%:具体点击链接。

 

list 和 array

ruby把数组叫用array。

python把数组叫list。

它们的方法类似,也不同。比如pop方法,ruby只去掉array最后的元素,而在python中pop(i)中的i可以指定删除索引i位置的元素。

还有,下面用":"来获得索引0,1,2的元素,然后组成一个新数组。

>> L[0:3]  

 

而Ruby使用"..."达到同样的作用。

python, “::”可以间隔取值。python管这个操作叫“切片”,也可以对string进行切片。

参考:https://docs.python.org/release/2.3.5/whatsnew/section-slices.html

例子: 第一个冒号:,左边是开始索引,右边是结束索引(但不包括结束索引自身),第二个冒号:, 右边是切片的距离。如果是负数,则先数据把反转,再切片。

>>> L = range(10)
>>> L[::2]
[0, 2, 4, 6, 8]

>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> s='abcd'
>>> s[::2]
'ac'
>>> s[::-1]
'dcba'

 

 

⚠️python统一使用len(variable)来得到变量的长度。

 

字符串的切片

例子:用切片的方法,把一个字符串的前后空格去掉。

# 循环:只要第一个字符是空格,就删除它。
# def trim(s):
#     while s[0:1] == " ":
#         s = s[1:]
#     while s[-1:] == " ":
#         s = s[:-1]
#     return s

# 递归:(纯递归,即返回值不是表达式并且它包括函数本身。本质上就是循环。)
def trim(s):
    if s[:1] == ' ':
        return trim(s[1:])
    elif s[-1:] == ' ':
        return trim(s[:-1])
    else:
        return s

 

 

 

特殊的tuple

tuple类型,其实就是list被冻结,只能读取不能修改。

用小括号代替中括号。

>>> t = (1, 2)
>>> t
(1, 2)

 

ruby中,用freeze方法来冻结数据。

⚠️如果只有一个数据要这么些,否则python会把小括号当成小括号而不是tuple符号:

>>> t = (1,)
>>> t
(1,)

 

 

数据类型的转换

ruby使用to_s, to_i, to_f方法来转换数据类型。

python使用int("1"),来把字符串"1"转换为整数类型。

 

条件判断:

python严格规定所有的<执行>都要缩紧相同位置,并且在<条件判断>后必须使用冒号,这种写法简化了传统的写法。

if <条件判断1>:
    <执行1>
elif <条件判断2>:
    <执行2>
elif <条件判断3>:
    <执行3>
else:
    <执行4>

 

ruby, 仅约定<执行>缩紧。无冒号,关键字end来结束条件判断。

 

字典,python对hash类型数据的定义

传统ruby核心模块有Hash类,用于对hash类数据进行操作。而python把这称为dict,即dictionary。

 

特殊的set

这是python独有的数据类型。用于储存一组key的集合。但不储存value。因为key是唯一的,所以set内没有重复元素。

 

>>> s1 = set([1, 2, 3])  #返回的是{1,2,3}
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}

 

循环

python 有2种循环 for..in..和while

for... in... , 遍历list或tuple种的元素。

Ruby也有for value in [1,2,3] do..end的写法。但很少在Ruby用到。(⚠️它不创建心的变量作用域)

但更强大的是Ruby的each方法,例如,Array.each方法相当于for..in。而且Hash等其他类也有each方法。用到的地方更多。

 


 

 

函数的理解

和其他语言大同小意。最基本的一种代码抽象的方式。

Python内置了很多有用的函数  https://docs.python.org/zh-cn/3/library/functions.html#abs

我的理解内置函数就相当于ruby中的核心代码库中的方法。但是调用的格式不同,ruby的格式是:object.method(args..)

Python内置函数类似javascript的调用。

这里⚠️一点。函数名字其实就是对函数的引用。所以,可以让变量指向函数名。通过变量调用函数。这类似javascript。

>>> a = abs # 变量a指向abs函数
>>> a(-1) # 所以也可以通过a调用abs函数
1

 

 

def定义

ruby和python都有关键字def。用于定义一个函数/方法。只是写法不同。其实ruby语言后来出了缩进的扩展包,但是不太流行。而python一开始就严格规定了缩进的写法。所以python没有end关键字,但增加了pass关键字。

⚠️冒号一定要有。

⚠️区别:return在def中必须有,否则返回None。因为return None等同于return。这点和ruby内不同。ruby的return可以省略。

 

pass关键字

这个关键字ruby没有,它的用途就是pass, 遇到它继续执行后面的代码。相当于占位符号。

这是因为python是缩紧写法,没有end关键字作为结束标志的原因。没有代码或pass关键字就报错了。

ruby由于有end所以即使每代码也不会报告错误。

>>> if True:
...
  File "<stdin>", line 2

    ^
IndentationError: expected an indented block

 

def可以返回多个值,还可以返回一个函数。

其实本质是返回一个tuple,里面包括了多个值。

ruby也可以,返回的是数组。

 

闭包closure

Python的def内可以获得外部变量,并修改外部变量。

但⚠️,内部如果使用声明=, 声明的变量名字和外部变量一样。那么def的内部作用域,将在后续代码中使用自己的内部变量。

当然,python为此增加了nonlocal语句,可以让被封装的代码重新绑定局部作用领域以外并且非全局作用于中的变量。 

 

函数的参数

python参数除了常规参数(就是位置参数),默认参数,可变参数,还有关键字参数。因此函数定义出来的接口,可以处理复杂的参数,还能简化调用者的代码。

默认参数

1. 默认参数必须放到必选参数后面。否侧会报告❌,SyntaxError: non-default argument follows default argument.

⚠️Ruby,没有这个限制,但也要求如果有多个默认参数,需要一起定义,中间不能再插个常规参数。

 

2. 在函数定义的时候,默认参数的值就被计算出来了。所以可能导致多次调用:add_end(),L会变成['END', 'END', ...]

def add_end(L=[]):
    L.append('END')
    return L

 

所以为了避免这种情况,默认参数的值必须指向不变对象:字符串,数值, None。不能是dict, set,list, tuple。

 

可变参数:

如果参数个数不确定。可以给参数加上*。类似,Ruby中, *参数也代表不定个数的参数。

可变参数本质是一个数组,python的函数接受到一个传入的tuple(即锁定的数组)。

def calc(*numbers):
    sum =for n in numbers:
        sum = sum + n * n
    return sum

>>> calc(1, 2)
5

#用*arg的形式,可以看成是调用函数时的简化版。
def calc(numbers):
    sum =for n in numbers:
        sum = sum + n * n
    return sum

>>>calc((1,2))
5

 

 

 

关键字参数

Ruby中,关键字参数相当于位置参数结合默认值。并且用**参数,代表多个关键字参数。(很少用到),而且⚠️位置参数,必须在关键字参数之前。

def add_values(first: 1, second: 2)
  first + second
end

def gather_arguments(first: nil, **rest)
  p first, rest
end

 

python和Ruby的用法类似: **参数就是任意个关键字参数。这些参数在函数调用时组装成一个dict,即一个hash类型。

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

 

前2个是位置参数,后一个是关键字参数,它可以传入0~任意个。

>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

 

关键字参数的用途:扩展函数的功能。比如:使用**extra把extra这个dict的所有key-value用做关键字参数传入到函数的**kw参数

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

⚠️插入函数的是extra的一份拷贝。

 

命名关键字参数

这是python灵活运用参数的一点体现。⚠️用*作为一个标记,后面的参数都是关键字参数。

它的目的是:限定可以传入的关键字:

def person(name, age, *, city, job):
    print(name, age, city, job)

如果传入其他key-value对儿,如果key没有找到,则传入失败。 

>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

 

另外,函数定义 时,有一个可变参数*args, 后面的参数都看成命名关键字参数。*args,代替了*。

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

 

⚠️注意的是,此时调用person函数,命名关键字参数必须传入,否则报告错误。

 

另外,Ruby有一个特殊的参数块参数。

def my_method(&my_block)
  my_block.call(self)
end

 

参数组合

python可以组合用必选参数(位置)、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。

它们的定义顺序: :必选参数、默认参数、可变参数、命名关键字参数和关键字参数。


⚠️使用的参数尽量不要太多组合,不方便理解和维护。

 

小结:

  • 默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
  • *args是可变参数,args接收的是一个tuple;
  • **kw是关键字参数,kw接收的是一个dict。
  • 可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3))

    关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})

  • 使用*args**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
  • 命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
  • 定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。

 


 

关闭

用微信“扫一扫”