I'm used to ruby and not python, but I have more opportunities to write python, so it feels like a memorandum.
Python is completely new to me. python 3. I decided not to care about python 2.x.
Processing system at hand
Confirmed in
ruby
ary_len = [1,2,3].size # [1,2,3].length is fine
hash_len = {a:1}.size # {a:1}.length is fine
string_len = "hoge".size # "hoge".length is fine
range_len = (1..9).size # Range#There is no length.
python3
ary_len = len([1,2,3])
dic_len = len({"a":1})
string_len = len("hoge")
range_len = len(range(1,10)) # 1〜9
Well this area is easy.
ruby
[].class #=> Array
1.class #=> Integer
[].is_a?(Enumerable) #=> true
Enumerable===[] #=> true
Enumerable==="" #=> false
[1,1.0,1r,1i].map{ |x| x.is_a?( Numeric ) } #=> [true, true, true, true]
python3
type([]) #=> <class 'list'>
type(1) #=> <class 'int'>
The process that seems to correspond to ruby's ʻEnumerable` is as follows:
python3
from collections import Iterable
isinstance([], Iterable) #=> True
isinstance("", Iterable) #=> True
Note that the ruby string is not Enumerable, but the python string is Iterable.
Below is an example of using a class like Numeric
in ruby in python:
python3
from numbers import Number
[isinstance(x,Number) for x in [1.0, 1, ""]] #=> [True,True,False]
Number and Iterable. Does that mean that importing will give you access to the name of the base class?
ruby
copied = [1,2,3].dup
python3
import copy
copied = copy.copy([1,2,3])
Python requires import to duplicate common objects. However, you can use the following idioms, methods, and constructors to copy the list:
python3
copied1 = [1,2,3][:] #Maybe this is normal.
copied2 = [1,2,3].copy()
copied3 = list([1,2,3]) #Maybe the constructor
dict also has a copy method:
python3
copied = {1:2}.copy()
copied = dict({1:2}) #Maybe the constructor
However. numpy's array is [:]
and cannot be copied.
import numpy as np
a=np.array([1,2,3])
b=a[:]
b[2]=100
print(a) #=> [ 1 2 100]
It's a trap. If you want to copy, use the copy method like b = a.copy ()
or use the constructor.
ruby
[]==[] #=>true ordinary comparison
[].equal?([]) #=>false Whether it points to the same object
python3
[]==[] #=>true ordinary comparison
[] is [] #=>false Whether it points to the same object
ruby
"hoge".to_s #=> 「hoge」
"hoge".inspect #=> 「"hoge"」
65.chr #=> "A"
python3
str("hoge") #=>「hoge」
repr("hoge") #=> 「'hoge'」
chr(65) #=> "A"
ruby
(1..10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[*1..10] #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
python3
list(range(1,11)) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ruby
[*10..100][10,3] #=> [20, 21, 22]
[*10..100][10..12] #=> [20, 21, 22]
python3
list(range(10,101))[10:13] #=> [20, 21, 22]
I wonder if there is any other way to write it.
ruby
a=[*1..5]
a[2,2]=9 # a[2,2]=[9]But the same.
a # => [1, 2, 9, 5]
python3
a=list(range(1,6))
a[2:4]=[9] # a[2:4]=Can't write 9
a #=> [1, 2, 9, 5]
There are various ways to write ruby, such as ʻa [2,2] = 9or ʻa [2..3] = [9]
, but python is only one of the above.
ruby
[1,2,3][-1] #=> 3
[1,2,3].last #=> 3
[1,3,5,7,9].last(2) #=> [7, 9]
python3
[1,2,3][-1] #=> 3
[1,3,5,7,9][-2:] #=> [7,9]
There doesn't seem to be a last method in python.
push / unshift
ruby
a=[1,2,3]
a.push 9
a.unshift 8
a #=> [8,1,2,3,9]
python3
a=[1,2,3]
a.append(9)
a.insert(0,8)
a #=> [8,1,2,3,9]
It seems that python doesn't have a dedicated method to add to the beginning.
pop / shift
ruby
a=[1,2,3,4]
b = a.pop
c = a.shift
[ a, b, c ] #=> [[2, 3], 4, 1]
d=[1,2,3,4]
e=d.pop(2) #Move the first two to e
[d,e] #=> [[1,2],[3,4]]
python3
a=[1,2,3,4]
b = a.pop()
c = a.pop(0)
[ a, b, c ] #=> [[2, 3], 4, 1]
d=[1,2,3,4]
e=d[-2:]
d[-2:]=[]
[d,e] #=> [[1,2],[3,4]]
In python, pop has an argument of where to get it, and if you specify 0, it will behave as shift
.
The python d [-2:] = []
can be del d [-2:]
.
It seems that python does not have a method equivalent to ruby's d.pop (2)
.
map
ruby
[1,2,3].map{ |x| x*2 } #=> [2,4,6]
%w( 1 2 3 ).map(&:to_i) #=> [1,2,3]
python3
[x*2 for x in [1,2,3]] #=> [2,4,6]
list(map(int,["1","2","3"])) #=>[1,2,3]
inject / reduce
ruby
[1,2,3].inject(0){ |acc,x| acc+x } #=> 6
[1,2,3].inject(0, &:+) #=> 6
python3
import functools
functools.reduce(lambda x,y:x+y, [1,2,3], 0) #=> 6
functools.reduce(int.__add__, [1,2,3], 0) #=> 6
In the above example, it is better to use ʻoperator.add instead of ʻint.__ add__
.
special thanks to antimon2: see http://qiita.com/Nabetani/items/50b0f6533a15d8fb2ae5#comment-bb3beb6fe012b4ebefe6
select
ruby
[1,2,3,4].select{ |x| x.even? } #=> [2, 4]
python3
[x for x in [1,2,3,4] if x%2==0 ] #=>[2, 4]
ruby
[1,5,13,21].max #=> 21
[1,5,13,21].max_by{ |x| x % 10 } #=> 5
python3
max([1,5,13,21]) #=> 21
max([1,5,13,21],key=lambda x:x%10 ) #=> 5
flatten
ruby
[1,[[2,3],4],5].flatten #=> [1,2,3,4,5]
There seems to be no flatten in python. see http://d.hatena.ne.jp/xef/20121027/p2
uniq
ruby
%w( f o o b a r b a z ).uniq #=> ["f", "o", "b", "a", "r", "z"]
python3
list(set("foobarbaz")) #=> ['z', 'f', 'b', 'a', 'o', 'r']The order is not saved
If you want to save the order, use Python Tips: I want to remove duplicate elements from the list.
ruby
[1,5,13,20].sort_by{ |x| x%10 } #=> [20,1,13,5]
python3
sorted([1,5,13,20], key=lambda x:x % 10 ) #=> [20, 1, 13, 5]
python sort is stable. ruby sort is not stable.
ruby
a=[1,3,5,7]
a.reverse #=> [7,5,3,1]Non-destructive
a.reverse! #Destructively reverse order
a #=> [7,5,3,1]
python3
a=[1,3,5,7]
list(reversed(a)) #=>[7, 5, 3, 1]Non-destructive
a[::-1] #=> [7, 5, 3, 1]Non-destructive
a.reverse() #Destructively reverse order
a #=> [7,5,3,1]
An amateur can't think of " :: -1
".
Note that the return value of reversed
is list_reverseiterator
, not list
.
zip
ruby
[1,2,3].zip(%w(a b c)) #=> [[1, "a"], [2, "b"], [3, "c"]]
[1,2,3].zip(%w(a b)) #=> [[1, "a"], [2, "b"], [3, nil]]
python3
list(zip([1,2,3],["a","b","c"])) #=> [(1, 'a'), (2, 'b'), (3, 'c')]
list(zip([1,2,3],["a","b"])) #=> [(1, 'a'), (2, 'b')]
ruby is matched to the receiver. python is adapted to the shorter one.
python doesn't become a list
just by zip
. If you pass it to the constructor of list
, it will be a list of tuples.
ruby
[1,2,3].sample #=> 1 or 2 or 3
[1,3,5].sample(2) #=> [5,3], [1,5]Such. Not duplicate.
python3
import random
random.choice( [1,2,3] ) #=> 1 or 2 or 3
random.sample( [1,3,5], k=2 ) #=> [5,3], [1,5]Such. Not duplicate.
ruby
rand
python3
import random
random.random()
ruby
rand(10)
Or
ruby
rng=Random.new
rng.rand(10)
rng.rand(0..9)
rng.rand(0...10)
python3
import random
random.randint(0,9)
The range specification of python includes both ends.
ruby
a=if 1.even?
"foo"
elsif 1.odd?
"bar"
else
"baz"
end
python3
if 1%2==0:
a="foo"
elif 1%2==1:
a="bar"
else:
a="baz"
In python, unlike ruby, if statements have no value. ruby's ʻelsif is python's ʻelif
. Also, there is no postfix if.
case〜when
Python has no control structure equivalent to case ~ when or switch ~ case.
ruby
10.times do |num|
do_something
end
loop do #infinite loop
break if some_condition
end
python3
for num in range(10):
do_something()
while True: #infinite loop
if some_condition():
break
In general, ruby has a lot of literals, but python doesn't (compared to ruby).
ruby
a=1.3r #=> (13/10)
python3
import fractions
fractions.Fraction(13,10) #=> 13/Value equivalent to 10
Rational number literals are not in python.
ruby
/.\s./.match("hello, world")[0] #=> ", w"
python3
import re
re.search( r".\s.", "hello, world" ).group(0) #=> ', w'
Regular expression literals are not in python. r "" is r, which means raw string.
ruby
"3**10=#{3**10}" #=> "3**10=59049"
python3
"3**10=%d" % 3**10 #=> "3**10=59049"
There is no expression expansion in python (it seems to be in 3.6. special thanks to norioc). You need to do something like printf.
ruby
print("hoge")
$stdout.flush()
print("hoge", end="", flush=True)
ʻImport sys may be
sys.stdout.flush () `.
ruby
print("hoge") #=>Output without trailing newline
puts("hoge") #=>Output with a newline at the end
python3
print("hoge", end="") #=>Output without trailing newline
print("hoge") #=>Output with a newline at the end
File.exist?("foo") #=>true if foo is file or directory
File.file?("foo") #=>true if foo is file
File.directory?("foo") #=>true if foo is directory
python3
import os
os.path.exists("foo") #=>true if foo is file or directory
os.path.isfile("foo") #=>true if foo is file
os.path.isdir("foo") #=>true if foo is directory
~~ python doesn't seem to have a method equivalent to ruby's File.exist?
. ~~
I was unaware that there was os.path.exists.
Thank you, @tokyo_gs.
ruby
a=File.open("hoge.txt"){ |f| f.read(10) }
python3
with open("hoge.txt") as f:
a=f.read(10)
Python will automatically close the file when you use with.
Assuming that f
is a file that can be taken with ʻopen`:
ruby
f.puts("hoge") #Newline at the end
f.print("fuga") #No line break at the end
f.write("piyo") #No line break at the end
python3
print("piyo", file=f) #Newline at the end
f.write("hoge") #No line break at the end
f.write("piyo\n") #Another way to add a newline at the end
Python cannot be written as f.print (abbreviation)
.
print (abbreviation, file = f)
was very surprising.
ruby
cond=true
val = cond ? "iftrue" : "iffalse"
python3
cond=True
val = "iftrue" if cond else "iffalse"
The conditional operation of python seems to be completely unfamiliar so far.
combination
ruby
[1,2,3].combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]]
python3
import itertools
list(itertools.combinations([1,2,3],2)) #=> [(1, 2), (1, 3), (2, 3)]
python is plural. The point is that it becomes a tuple.
There is also permutations
.
Thread
ruby
Array.new(4){ |ix| Thread.new{ print ix } }.each(&:join) #=>2103
python3
import threading
ts=[threading.Thread(target=(lambda x=x:print(x))) for x in range(4)]
for t in ts:
t.start()
for t in ts:
t.join()
The block of ~~ ruby uses the reference of the value when capturing the variable, so if you write it normally (it is an individual impression), it will work. ~~
2018/3/17 Correction
I think ruby works because a variable called ix is confined in scope and generated every time.
/ 2018/3/17 Correction
For python, the default argument is suspicious, but if you use lambda, it will not work unless you do this or double it. The reason is that python's lambda captures variable references. (Isn't it right?) If this is unpleasant, you can specify the method in target without using lambda.
uuid
ruby
require 'securerandom'
SecureRandom.uuid #=> => "72568c47-e6e0-4f21-a8b5-dad3d72831b2"
python3
import uuid
str(uuid.uuid4()) #=> '9414a2d6-b954-4519-bf88-47828d6d2577'
You can create secure random numbers with a module called secrets, but since python 3.6. Moreover, there seems to be no I / F that creates a uuid.
The uuids for python are ʻuuid1 () , ʻuuid3 ()
, ʻuuid4 () , ʻuuid5 ()
.
ʻUuid4 ()seems to correspond to ruby's
SecureRandom.uuid`.
It's not a thread join, but a comma that connects the elements of an array.
ruby
[1,"hoge",2.34].join(",") #=> "1,hoge,2.34"
python3
",".join([str(x) for x in [ 1, "hoge", 2.34 ] ] ) #=> '1,hoge,2.34'
When ruby joins, it becomes a string without permission, but python can only join a string. I knew that the receiver was the other way around, but I didn't know that it wouldn't convert it to a string.
ruby
"a,b,c".split(",") # => ["a", "b", "c"]
"a-b+c".split(/\W/) # => ["a", "b", "c"]
python3
import re
"a,b,c".split(",") #=> ["a", "b", "c"]
re.split(r"\W", "a+b-c") #=> ["a", "b", "c"]
re.compile( r"\W" ).split( "a+b-c" ) #=> ["a", "b", "c"]
It is necessary to change the name depending on whether it is a regular expression or not.
It's a pity that you can't write " a, b, c ".split (re.compile (r" \ W "))
.
Will be added. There is a better way to write it! Call for opinions.
Recommended Posts