Подтвердить что ты не робот

Как создать код в Python?

Я прихожу из Java и изучаю Python. До сих пор то, что я нашел очень классным, но очень трудно адаптироваться, заключается в том, что нет необходимости объявлять типы. Я понимаю, что каждая переменная является указателем на объект, но пока я не могу понять, как создать код.

Например, я пишу функцию, которая принимает массив 2D NumPy. Тогда в теле функции я вызываю различные методы этого массива (который является объектом array в Numpy). Но затем в будущем предположим, что я хочу использовать эту функцию, к тому времени я мог бы полностью забыть, что я должен передать функции как тип. Что люди обычно делают? Они просто пишут для этого документацию? Потому что, если это так, то это требует большего набора текста и поставит вопрос о том, чтобы не объявлять тип.

Также предположим, что я хочу передать объект, похожий на массив в будущем. Обычно в Java реализуется интерфейс, а затем пусть оба класса реализуют методы. Затем в параметрах функции я определяю переменную типа интерфейса. Как решить эту проблему на Python или какие подходы могут быть использованы для создания одной и той же идеи?

4b9b3361

Ответ 1

Это очень здоровый вопрос.

Утиная печать

Первое, что нужно знать о python, - это концепция утиной печати:

Если он ходит, как утка, и крякает, как утка, тогда я называю это уткой

В отличие от Java, типы Python никогда не объявляются явно. Нет ограничений, ни во время компиляции, ни во время выполнения, в типе, который может принять объект.

То, что вы делаете, просто обрабатывает объекты так, как если бы они были идеального типа для ваших нужд. Вы не спрашиваете или не задаетесь вопросом о его типе. Если он реализует методы и атрибуты, которые вы хотите получить, то это. Это будет сделано.

def foo(duck):
    duck.walk()
    duck.quack()

Единственный контракт этой функции состоит в том, что duck предоставляет walk() и quack(). Более утонченный пример:

def foo(sequence):
    for item in sequence:
        print item

Что такое sequence? A list? Числовое значение array? A dict? A generator? Это не имеет значения. Если он повторяется (т.е. Он может использоваться в for ... in), он выполняет свою задачу.

Тип подсказки

Конечно, никто не может жить в постоянном страхе перед объектами неправильного типа. Это рассматривается с помощью стиля кодирования, условных обозначений и хорошей документации. Например:

  • Переменная с именем count должна содержать целое число
  • Переменная Foo, начинающаяся с буквы верхнего регистра, должна содержать type (class)
  • Аргумент bar, значение которого по умолчанию False, также должен содержать bool при переопределении

Обратите внимание, что к этим 3 примерам можно применить концепцию типирования утки:

  • count может быть любым объектом, который реализует +, - и <
  • Foo может быть любым вызываемым, возвращающим экземпляр объекта
  • bar может быть любым объектом, который реализует __nonzero__

Другими словами, тип никогда не определяется явно, но всегда сильно намекает. Вернее, возможности объекта всегда намекают, а его точный тип не имеет значения.

Очень распространено использование объектов неизвестных типов. Большинство фреймворков выставляют типы, которые выглядят как списки и словари, но не являются.

Наконец, если вам действительно нужно знать, там есть документация. Вы найдете документацию python значительно превосходящую для Java. Это всегда стоит прочитать.

Ответ 2

Я просмотрел много кода на Python, написанных разработчиками Java и .Net, и я неоднократно видел несколько проблем, о которых я мог бы предупредить/сообщить:

Python не является Java

Не вставляйте все в класс:

Похоже, что даже самая простая функция завершается, завернувшись в класс, когда разработчики Java начинают писать Python. Python - это не Java. Не записывайте геттеры и сеттеры, для чего предназначен декоратор свойств.

У меня есть два предиката, прежде чем я буду рассматривать классы:

  • Я выхожу замуж за состояние с функциональностью
  • Я ожидаю, что у меня будет несколько экземпляров (в противном случае уровень модуля и функции в порядке!)

Не печатайте - проверяйте все

Python использует утиную печать. См. Модель данных. Его встроенное принуждение - ваш друг.

Не помещайте все в блок try-except

Исключайте только исключения, которые, как вы знаете, получите, используя исключения во всем мире для потока управления, являются дорогостоящими вычислениями и могут скрыть ошибки. Попробуйте использовать наиболее конкретное исключение, которое вы ожидаете получить. Это приводит к созданию более надежного кода в долгосрочной перспективе.

Изучите встроенные типы и методы, в частности:

Из модели данных

str

  • join
  • просто сделайте dir(str) и изучите их все.

list

  • append (добавьте элемент в конец списка)
  • extend (расширьте список, добавив каждый элемент в итерируемый)

dict

  • get (укажите значение по умолчанию, которое не позволяет вам захватывать ключевые слова!)
  • setdefault (устанавливается по умолчанию или уже имеющееся значение!)
  • fromkeys (постройте dict со значениями по умолчанию из итерируемого ключей!)

set

Наборы содержат уникальные (без репликации) хешируемые объекты (например, строки и числа). Мышление диаграммы Венна? Хотите узнать, есть ли набор строк в наборе других строк или какие перекрытия (или нет?)

  • union
  • intersection
  • difference
  • symmetric_difference
  • issubset
  • isdisjoint

И просто сделайте dir() для каждого типа, с которым вы сталкиваетесь, чтобы увидеть методы и атрибуты в своем пространстве имен, а затем выполните help() для атрибута, чтобы узнать, что он делает!

Изучите встроенные функции и стандартную библиотеку:

Я поймал разработчиков, которые пишут свои собственные функции max и устанавливают объекты. Это немного неловко. Не позволяйте этому случиться с вами!

Важными модулями, которые должны быть в стандартной библиотеке, являются:

  • os
  • sys
  • collections
  • itertools
  • pprint (я использую его все время)
  • logging
  • unittest
  • re (регулярные выражения невероятно эффективны при разборе строк для большого количества случаев использования)

И просмотрите документы для краткого ознакомления с стандартной библиотекой, здесь Часть 1 и здесь Часть II. И вообще, сделайте снимок всех документов ранней целью.

Прочтите руководства по стилям:

Вы узнаете много о лучших практиках, просто прочитав свои руководства по стилю! Я рекомендую:

Кроме того, вы можете узнать отличный стиль по Googling по проблеме, которую вы изучаете, с фразой "лучшая практика", а затем выбрав соответствующие ответы Stackoverflow с наибольшим количеством upvotes!

Я желаю вам удачи на пути к изучению Python!

Ответ 3

Например, я пишу функцию, которая принимает массив 2D Numpy. Тогда в теле функции я вызываю различные методы этого массива (который является объектом массива в Numpy). Но тогда в будущем предположим, что я хочу использовать эту функцию, к тому времени я мог бы полностью забыть, что я должен передать функции как тип. Что люди обычно делают? Они просто пишут для этого документацию?

Вы пишете документацию и соответствующим образом называете функцию и переменные.

def func(two_d_array): 
    do stuff

Также предположим, что в будущем я хочу передать объект, похожий на массив, как правило, в Java, который реализует интерфейс, а затем пусть оба класса реализуют методы.

Вы можете это сделать. Создайте базовый класс и наследуйте его, чтобы несколько типов имели один и тот же интерфейс. Однако, довольно часто, это излишне, и вместо этого вы просто используете утиную печать. С утиным набором текста все, что имеет значение, - это то, что оцениваемый объект определяет правильные свойства и методы, необходимые для его использования в вашем коде.

Обратите внимание, что вы можете проверить типы в Python, но это обычно считается плохой практикой, поскольку это мешает вам использовать утиную печать и другие шаблоны кодирования, включенные системой динамического типа Python.

Ответ 4

Да, вы должны документировать, какие типы аргументов ожидаются вашими методами, и до вызывающего, чтобы передать правильный тип объекта. Внутри метода вы можете написать код для проверки типов каждого аргумента или просто предположить его правильный тип и полагаться на Python, чтобы автоматически генерировать исключение, если переданный объект не поддерживает методы, которые ваш код необходимо вызвать его.

Недостаток динамической типизации заключается в том, что компьютер не может выполнить такую ​​же проверку правильности переднего плана, как вы отметили; есть большая нагрузка на программиста, чтобы убедиться, что все аргументы имеют правильный тип. Но преимущество в том, что у вас гораздо больше гибкости в том, какие типы могут быть переданы вашим методам:

  • Вы можете написать метод, который поддерживает несколько различных типов объектов для конкретного аргумента, без необходимости перегрузки и дублированного кода.
  • Иногда метод действительно не заботится о точном типе объекта, если он поддерживает определенный метод или операцию - скажем, индексирование с квадратными скобками, которое работает с строками, массивами и множеством других вещей. В Java вам нужно создать интерфейс и написать классы-оболочки для адаптации различных ранее существующих типов к этому интерфейсу. В Python вам не нужно ничего делать.

Ответ 5

Вы можете использовать assert для проверки соответствия условий:

In [218]: def foo(arg):
     ...:     assert type(arg) is np.ndarray and np.rank(arg)==2, \
     ...:         'the argument must be a 2D numpy array'
     ...:     print 'good arg'

In [219]: foo(np.arange(4).reshape((2,2)))
good arg

In [220]: foo(np.arange(4))
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-220-c0ee6e33c83d> in <module>()
----> 1 foo(np.arange(4))

<ipython-input-218-63565789690d> in foo(arg)
      1 def foo(arg):
      2     assert type(arg) is np.ndarray and np.rank(arg)==2, \
----> 3         'the argument must be a 2D numpy array'
      4     print 'good arg'

AssertionError: the argument must be a 2D numpy array

Всегда лучше документировать то, что вы написали полностью, как упоминал @ChinmayKanchi.

Ответ 6

Вот несколько указателей, которые могут помочь вам сделать ваш подход более "Pythonic".

PEPs

В общем, я рекомендую по крайней мере просматривать PEPs. Мне очень помогли Python.

Указатели

Поскольку вы упомянули указатели на слова, Python не использует указатели на объекты в том смысле, что C использует указатели. Я не уверен в отношении к Java. Python использует имена, прикрепленные к объектам. Это тонкое, но важное отличие, которое может вызвать у вас проблемы, если вы ожидаете поведения указателя с аналогичным положением.

Duck Typing

Как вы сказали, да, если вы ожидаете определенный тип ввода, вы помещаете его в docstring.

Как писал zhangxaochen, вы можете использовать assert для выполнения ввода в реальном времени своих аргументов, но это не совсем путь python, если вы делаете это все время без особых причин. Как уже упоминалось, лучше проверить и поднять TypeError, если вам нужно это сделать. Python предпочитает вместо утиного набирать текст - если вы посылаете мне что-то такое, что quacks, как многомерный 2D-массив, тогда это прекрасно.