Портування Scala у Python

5 хв. читання

Не так давно мені довелося портувати 16 тис. рядків коду на Scala у Python. Справа успішно зроблена і зараз я хочу поділитися отриманими навичками. Перш ніж я почну, хотілось би сказати, що Scala - це дуже класна мова і я сподіваюся мати можливість працювати зі Scala знову в найближчому майбутньому.

1. Пари ключ-значення в словниках Python і картах Scala мають різний порядок

Python не зберігає порядок, у якому елементи додаються в словник. Я думаю, найкраще проілюструвати це на прикладі:

>>> # давайте створимо словник
>>> d = {'key_a': 'value_a', 'key_b': 'value_b', 'key_c': 'value_c'}
>>>
>>> # і виконаємо ітерацію пар ключ/значення
>>> for item in d.items():
...   print item
... 
('key_a', 'value_a')
('key_c', 'value_c')
('key_b', 'value_b')

Бум - все переплутано! Той же фрагмент в Scala:

scala> // створимо карту
scala> val m = Map("key_b" -> "value_b", 
     |             "key_c" -> "value_c", 
     |             "key_a" -> "value_a")
scala> 
scala> // виконаємо ітерацію пар ключ/значення
scala> m.map(item => println(item))

(key_b,value_b)
(key_c,value_c)
(key_a,value_a)

В той час як Python сортує елементи словника неочевидним чином, Scala зберігає порядок елементів таким, яким вони були додані в карту. На жаль, мені довелося зрозуміти це стикаючись зі складнощами - деякі частини коду припускали "правильний" порядок елементів. На щастя, це можна було легко виправити з OrderedDict.

2. Будьте обережні при перевірці має змінна числове значення чи ні

Наприклад цей простий фрагмент коду перевіряє, чи є x NaN чи ні:

scala> val x = Double.NaN
scala>
scala> if(x.isNaN) {
            println("x не має значення")
        } else {
            println("x має значення")
        }

x не має значення

Еквівалент в Python:

>>> x = None
>>> if not x:
...   print "x не має значення"
... else:
...   print "x має значення"
... 
x не має значення

Поки все добре. Але іноді хочеться скористатися NumPy для виконання деяких обчислень в більш елегантний спосіб. Краще використати NumPy NaN значення замість None. Я не кажу, що це помилка мови програмування, але потрібно бути особливо обережним, коли ви пишете щось на зразок цього:

>>> import numpy as np
>>>
>>> x = np.NaN
>>> if not x:
...   print "x не має значення"
... else:
...   print "x має значення"
... 
x має значення

Звичайно, це було не те, що я мав на увазі! Подібна "аномалія" може виникнути, якщо x дорівнює 0 і, отже, вже має значення:

>>> x = 0
>>> if not x:
...   print "x не має значення"
... else:
...   print "x має значення"
... 
x не має значення

Такі моменти дуже легко випустити з уваги будучи на автопілоті.

3. Перенесення класів з кількома конструкторами

Припустимо, ми маємо наступний код Scala:

class Person(val firstName: String, val lastName: String) {

  def this(firstName: String) {
    this(firstName, "");
  }

  def this(firstName: String, lastName: String) {
    this(firstName, lastName);
  }
}

Як портувати це в Python? Це, насправді, дуже велика проблема, так як в Python більше не має підтримки декількох конструкторів. Єдине розумне рішення, яке я зміг придумати, було:

class Person:
  def __init__(self, first_name, last_name):
    self.first_name = first_name
    self.last_name = last_name

  @staticmethod
  def create(*args):
    if len(args) == 1:
      return Person(args[0], None)
    elif len(args) == 2:
      return Person(*args)
    else:
      raise Exception("Неправильна кількість аргументів: %s" % len(args))

І ви використовуєте його так:

shrek = Person.create("Shrek")
hugh = Person.create("Hugh", "Jass")

Звичайно, що може бути випадок, коли один конструктор приймає рядок, а інший - ціле число або щось інше. В даному випадку це, ймовірно, кращий спосіб перевірки типу змінної. Щось на зразок цього:

>>> x = 5
>>> type(x) == int
True
>>> type(x) == str
False

4. Спершу - перенесення, потім - рефакторинг

Рішення в останньому абзаці далекі від ідеалу, але принаймні ми не змінюємо логіку коду при його перенесенні. Просто не виконуйте рефакторинг коду до того моменту, поки ви не зрозуміли, що там відбувається на 100%. Якщо, звичайно, ви не хочете мати неприємні. І це загальне правило, а не лише у випадку "Scala-to-Python".

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 6.2K
Приєднався: 7 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація