

Ruby to Python Translation Guide
source link: https://fuzzyblog.io/blog/python/2019/12/11/ruby-to-python-translation-guide.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Last Update: 12/12/2019
I wrote this guide to different Ruby idioms and how to do them in Python. Organization is alphabetical. This will have to be a continually updated document as I keep finding holes in my Python knowledge and my prior practice of "Learn it / Blog it" simply doesn't put enough things into the same place. I need a single, easily searchable place to store all this random "how to do X cruft".
This is written as headings which discuss the problem and then how it is done in Ruby and in Python and then, optionally, a Python context. Hopefully this approach makes it useful to both ruby-ites and python-istas.
Note 1: My day to day lingua franca is still Ruby and in a Rails style context where everything is autoloaded. Python to me is a specialized tool for Data Science / Machine Learning. I find that Python:
- Lacks the elegant simplicity of Ruby
- Python syntax makes my eyes want to bleed, can we have an underscore character please, how about a colon or some more parentheses
- Is developer hostile by default
Note 2: These are opinions! I am writing them after a craptastic work day so that and lack of sleep may be tilting my opinions more than a bit; I mean I'm right but still … And please understand that I fundamentally respect that amazing work that Guido did but I find myself in Matz's camp by preference. Still nothing else has the ecosystem that Python does.
Note 3: If you disagree with the above, my twitter handle is fuzzygroup and my email is easily discoverable. Let the fun begin …
Note 4: This was initially written in late 2019 so the Python flavor / version is 3.7 using VirtualEnv on a Mac with pip3.
Note 5: If there's things you want to see here then actually do let me know. This isn't a planned out document, it is more of a "what made me feel stooopid in Python today" type of thing.
Debugging
The ruby is:
byebug
The python is:
pdb.set_trace()
Getting All Attributes of an Object
Most Ruby objects, at least in a Rails context, are generally ActiveRecord objects and respond to .attributes so:
plan = Plan.first
2.6.3 :016 > plan.attributes
{
"id" => 1,
"created_at" => Sat, 27 Jul 2019 08:28:17 UTC +00:00,
"updated_at" => Sat, 27 Jul 2019 08:28:17 UTC +00:00,
"name" => "Write Daily",
"public_name" => nil,
"description" => nil,
"options" => nil,
"user_id" => 1,
"category_id" => nil,
"has_habits" => nil,
"habit_count" => 3,
"shareable" => false,
"master_plan" => false,
"active" => true
}
The python equivalent of this is is to reference the object's internal dict. Below we have an object called message which is coming in from a streaming data solution called sse:
message.__dict__
{'data': '{"all_awardings":[],"approved_at_utc":null,"ups":1,"user_reports":[]}', 'event': 'rc', 'id': '33288433929', 'retry': None}
# There are four different top level things that can be called:
message.data
message.event
message.id
message.retry
# despite the appearance, the attributes of data are NOT json buy just a string so this doesn't work:
message.data.keys()
*** AttributeError: 'str' object has no attribute 'keys'
Getting All Methods for an Object
The ruby is:
hash = {'foo': 'bar', 'cat': 'blepp'}
(hash.methods - Object.methods).sort
(hash.methods - Object.methods).sort
[
[ 0] :[],
[ 1] :[]=,
[ 2] :all?,
[ 3] :any?,
[ 4] :assert_valid_keys,
[ 5] :assoc,
[ 6] :chain,
[ 7] :chart_json,
[ 8] :chunk,
# a crap ton of methods omitted for clarity
]
# Also and BETTER since it just shows methods on the class; not inherited methods:
plan.public_methods(false)
[
[ 0] active_habits() Plan
[ 1] after_add_for_habits() Plan
[ 2] after_add_for_habits=(val) Plan
[ 3] after_add_for_habits?() Plan
[ 4] after_remove_for_habits() Plan
[ 5] after_remove_for_habits=(val) Plan
[ 6] after_remove_for_habits?() Plan
[ 7] autosave_associated_records_for_habits(*args) Plan
[ 8] before_add_for_habits() Plan
[ 9] before_add_for_habits=(val) Plan
[10] before_add_for_habits?() Plan
[11] before_remove_for_habits() Plan
[12] before_remove_for_habits=(val) Plan
[13] before_remove_for_habits?() Plan
[14] foo(bar) Plan
[15] validate_associated_records_for_habits(*args) Plan
]
The python is:
dir(message)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'data', 'dump', 'event', 'id', 'parse', 'retry', 'sse_line_pattern']
(Pdb) message.sse_line_pattern
re.compile('(?P<name>[^:]*):?( ?(?P<value>.*))?')
# object.__dict__ gets you an object's data while dir(object) gets you an object's methods
See: Me, Lerner, Swlh, Stack Overflow
Getting All Keys in a Hash
The ruby is:
hash = {'foo': 'bar', 'cat': 'blepp'}
2.6.3 :018 > hash.keys
[
[0] :foo,
[1] :cat
]
The python is:
hash = {'foo': 'bar', 'cat': 'blepp'}
hash.keys()
dict_keys(['foo', 'cat'])
JSON Parsing
The ruby is:
json_str = '{"id": 12345, "message": "hello", "array": [1,2,3,4]}'
json = JSON.parse(json_str)
{
"id" => 12345,
"message" => "hello",
"array" => [
[0] 1,
[1] 2,
[2] 3,
[3] 4
]
}
The python is:
import ujson as JSON
json_str = '{"id": 12345, "message": "hello", "array": [1,2,3,4]}'
json = JSON.loads(json_str)
{'id': 12345, 'message': 'hello', 'array': [1, 2, 3, 4]}
json.keys()
dict_keys(['id', 'message', 'array'])
I will confess to dipping into a bit of a Ruby idiom here by importing ujson as JSON (all caps). I find myself constantly making errors in python by calling my json variable json when that's actually an imported class / module. This one change makes things a lot easier (at least for me).
Length / Size of an Object
The ruby is:
plan.name.size
11
The python is:
len(message.data)
1826
Quitting the console
The ruby is:
quit
The python is:
quit()
Redis
The ruby is:
require 'redis'
2.6.3 :005 > redis = Redis.new
#<Redis client v4.1.3 for redis://127.0.0.1:6379/0>
2.6.3 :006 > redis.set("mykey", "hello world")
"OK"
2.6.3 :007 > redis.get("mykey")
"hello world"
The python is:
>>> import redis
>>> r = redis.Redis(host='localhost', port=6379, db=0)
>>> r.set('mykey', 'hello world')
True
>>> r.get('mykey')
'hello world'
String Interpolation
The ruby is:
skill = "beginner"
puts "Scott is a #{skill}"
The python is:
skill = "beginner"
print(f"Scott is a {skill}")
Try / & - Safe Navigation and Python Hashes
A ruby hash returns nil if the key specified is missing:
ENV['foo']
nil
2.3.1 :003 > ENV['RUBY_VERSION']
"ruby-2.3.1"
A python dict raises an exception:
import os
>>> os.environ['RAILS_ENV']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/sjohnson/Sync/fuzzygroup/adl/antihate/antihate_experts/venv/bin/../lib/python3.7/os.py", line 678, in __getitem__
raise KeyError(key) from None
KeyError: 'RAILS_ENV'
>>> os.environ.get('RAILS_ENV')
>>> os.environ.get('RUBY_VERSION')
'ruby-2.3.1'
The ruby way around this would be to use try or the safe navigation operator:
https://stackoverflow.com/questions/46390057/from-ruby-to-python-is-there-an-equivalent-of-try
The Blank for Writing the Next Entry
The ruby is:
The python is:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK