Вопросы пара языка эргономики, которые дали мне неприятности в моих нескольких годах написания питона.
Декларации выполняются
Это тот, который имеет смысл после того, как вы думаете о том, что происходит, но я думаю, что легко ошибиться в первый раз.
Одним из примеров является следующее:
class MyClass: def __init__(self, data={}): self._data = data def set(self, k, v): self._data[k] = v def get(self, k): return self._data.get(d) def remove(self, k): self._data.pop(k, None) def get_count(self): return len(self._data.keys()) A = MyClass() A.get_count() # 0 A.set('a', 1) A.get_count() # 1 B = MyClass() B.get_count() # 1 A.remove('a') A.get_count() # 0 B.get_count() # 0
Если вы экспериментировали дальше, вы увидите, что содержимое _data
как-то хранится в синхронизации между обоими экземплярами MyClass
Отказ
Но интересно:
C = MyClass({}) C.get_count() # 0
Что случилось, так это то, что Python получает определения класса и функции, выполняя строку файла по строке, что означает, что значение по умолчанию данные
в __init__
метод фактически создан. Все экземпляры класса, которые используют значение значения по умолчанию, и прочитайте из одного и того же объекта, эффективно делая его переменной класса.
Это подтверждается:
A._data is B._data # True
Избегать этого включает в себя что-то тупые, как:
class MyClass: def __init__(self, data=None): if data is None: self._data = {} else: self._data = data ...
Область объема переменных петлей
В отличие от многих языков, «петлевые переменные» в Python остаются в локальном объеме после выхода на петлю. Это может привести к некоторому неожиданному поведению:
def fun(): i = 0 arr = [1, 2, 3] # lots of code for i in range(len(arr)): # do some stuff # more code return arr[i] fun() # returns 3
В то время как этот пример довольно придумывался, общая идея состоит в том, что это поведение переменных петлей может привести к странным и трудностями к ошибкам (включая этот пример затенения ранее объявленных локальных переменных).
Еще одно осложнение: если для цикла нет, переменные петли не будут назначены вообще. Например, первая строка Главная ()
Ниже проходит без ошибки, но вторая строка приведет к тому, что вторые строки приведут NameError: Имя 'x' не определяется
быть воспитанным.
def fun(l): for x in l: print(x) return x def main(): fun([1, 2, 3]) fun([])
Даже другие интерпретированные и не в курсыми языкам, связанные с людьми, например, избегают этих неприятностей, например Рубин:
3.times do |x| print x end x # NameError (undefined local variable or method `x' for main:Object)
Цепочка функций сложно
Когда дело доходит до работы с структурами данных, предоставляемые функции и методы Python не очень последовательны. Принять список, например: Список
У класса есть методы, которые меняют его на месте, но для многих операций вам понадобится для использования списка, которые возвращают новые списки и имеют уникальный синтаксис. Для других операций вы можете использовать фильтр
и карта
, которые являются функциями (не методы класса списка). И есть другие рассеянные несоответствия, например, тот факт, что Присоединяйтесь к
, функция для работы со списками, представляет собой строковый метод вместо способа списка.
Например:
def slugify(string, bad_words): words = string.split() words = [w.lower() for w in words if w.isalpha() and w not in bad_words] return "-".join(words) slugify("My test 1 string", set(["dang", "heck"])) # "my-test-string"
Для людей, знакомых с Python, это, вероятно, выглядит естественным, но даже по-прежнему код требует тщательного чтения для понимания каждого преобразования. Функция делает (и это для простого примера).
На других языках этот вид кода более естественный. Ruby, например, имеет более последовательные методы, которые позволяют цепочку:
def slugify(string, bad_words) string.split() .map(&:downcase) .select { |w| w.match(/^[[:alpha:]]+$/) } .select { |w| !bad_words.include? w } .join("-") end slugify("My dang test 1 string", Set["dang", "heck"]) # "my-test-string"
В качестве примера функционального мира Clojure решительно поддерживает цепочку функций с постоянными API и резьбой макросов ->
и - >>
Отказ
(defn slugify [string bad-words] (->> (str/split string #" ") (filter #(re-matches #"^[a-zA-Z]*$" %)) (remove bad-words) (map str/lower-case) (str/join "-") ) ) (slugify "My dang test 1 string" (set '("dang" "heck"))) ; "my-test-string"
Оригинал: “https://dev.to/cselig/my-least-favorite-python-quirks-54j3”