Pull to refresh

Comments 35

привычнее 'атрибут' > 'поле'
поле класса (классовое поле) и поле экземпляра (инстанса) класса. возможно в разных языках по-разному, конечно, но в жаве рекомендуют так:
stackoverflow.com/questions/10115588/what-is-the-difference-between-field-variable-attribute-and-property-in-java
Attribute is a vague term. It can easily be confused with XML or Java Naming API. Try to avoid using that term.

В самом начале "Примеры классов в Python и Java"


И приведены разные классы. В примере Java приватные поля и методы доступа, а в примере Python — публичные поля.

В Java при создании классов на автомате прячут поля (правила хорошего тона), в Python их просто помещают в __init__ (делая публичными). Не знаю, кто в Python-е сразу делает их скрытыми (и нужно ли это делать вообще). Поэтому классы аналогичны с точки зрения написания их по умолчанию.
Насчёт «хорошего тона» в Java, это всё-таки вкусовщина и по большой части уже далеко не все ей следуют (к месту и не к месту, как раньше).
Боюсь, после прочтения статьи у читателей создастся ложное представление и вместо лаконичного и в большинстве случаев подходящего

public class Car {
  private final String color;
  private final String model;
  private final int year;

  public Car(String color, String model, int year) {
    this.color = color;
    this.model = model;
    this.year = year;
  }
}


они будут нести в массы бесполезные геттеры/сеттеры.

Посоветовал бы автору статьи сделать похожие исследования Python/Kotlin, которые более похожи в плане синтаксиса.
UFO just landed and posted this here
Как раз вчера закончил проходить на Codecademy вводный курс по Python и задумался о различиях между ним и Java. Спасибо за статью, мне пригодилось.
UFO just landed and posted this here
В java, если нужны просто свойства бина используется Introspector или BeanUtil какой-нибудь… рефлексия немного низкоуровнева для данной конкретной задачи…
class Car:
     def __init__(self, color, model, year):
         self.color = color
         self.model = model
         self.year = year

это конечно стандартный питон, но с моей точки зрения намного лучше выглядить такая запись с использованием сторонней библиотеки:
import attr

@attr.s(auto_attribs=True)
class Car:
    color: str
    model: str
    year: int

так работает вроде начиная с версии 3.6, в более старых тип немного по другому указывается, но всё равно лучше чем дефолтный способ.
Ну и эта библиотека сразу создаёт нормальные дандер-методы, вобщем позволяет не писать горы шаблонного кода.
ну это частный случай, если это датакласс, хотя технически не запрещено вроде м для других задач юзать, но тут вопрос семантики
«self» в Питоне — это просто параметр функции. Вы его можете даже переименовать, например в «foobar» и ничего не поменяется. А в Java «this» — это ключевое слово языка, которое всегда ссылается на объект, к которому относится метод.

В Python же «встроенной» ссылки на текущий объект нету, так как в Питоне методы класса — это на самом деле обычные функции, которые фактически ничего не знают про то, что они привязаны к какому-то классу. Просто Питон при вызове метода на экземпляре класса передает в функцию первым аргументом ссылку на этот объект.

Из-за такой особенности Питона, в частности, возможны всякие «грязные трюки » вроде вызова метода одного класса в контексте экземпляра совсем другого класса, что в Java в принципе невозможно (и к лучшему).

В жабе рефлексией можно получит метод/поле одного класса и потом пытаться вызвать его для объекта другого класса. Как бы велком, один вопрос — на… зачем?

При попытке такого вызова вы немедленно получите ClassCastException или какой-нибудь InvocationException. Непосредственно сделать вызов — не выйдет (к счастью).

один вопрос — на… зачем?
Пример с таким вызовом — всего лишь способ показать фундаментальное различие между обсуждаемыми ЯП.

Если метод интерфейсный и класс его реализует то всё будет окай. Вопрос в другом. Зачем сравнивать разные языки по своей природе? Строго типизированный типа жабы с питоном. Компмлируемый со скриптовым. Естественно различия будут. Но примеры сравнивания с трамвайной ручкой это следствия, а не индикаторы различий.

в Питоне методы класса — это на самом деле обычные функции, которые фактически ничего не знают про то, что они привязаны к какому-то классу

Зачем же так подставляться? Когда надо — они кое-что знают:
myformat = "<{}>".format
print(myformat("qwe"))
Вы передали в функцию первым аргументом экземпляр класса, т.е. явно ей сказали: вот тебе объект, работай с ним. Где здесь как-то используется знание функции о том, что она относится к какому-то классу?
Вы передали в функцию первым аргументом экземпляр класса

Если бы я сделал то, что вы мне приписываете, я бы сделал это так:
str.format("<{}>", "qwe")
Улавливаете разницу?

На самом деле я обратился к экземпляру класса: поищи-ка у себя что-то по имени format. И он (экземпляр класса) таки нашел у себя метод с этим именем.

И да: если не улавливаете — не утруждайте себя ответом.
А вы улавливаете разницу между A.method и A().method?

В первом случае — это как раз-таки метод класса, который действительно является функцией и ничего не знает о том, к какому классу он прикреплён. Во-втором — это bound method.
Ох спасибо, что просветили, скопирую к себе в избранное.
И спорить с вами не буду — вы вишь какой умный.
Из-за такой особенности Питона, в частности, возможны всякие «грязные трюки » вроде вызова метода одного класса в контексте экземпляра совсем другого класса

Мне кажется, вы нас обманываете. Можете продемонстрировать конкретно этот описанный вами приём?
def method(boku, val):
  boku.field = val

class A:
  def __init__(self):
    self.field = 3
  def test(self):
    print(self.field)

class B:
  pass

class C:
  def __init__(self):
    self.field = 7

b = B()
B.test = A.test
B.method = method
b.method(12)
b.test()
A.test(C())
Судя по примеру, вы говорите про питон3. Мне следовало уточнить, что интересует этот хак в питоне2, ибо там такое не прокатит.

Но все равно спасибо за ответ.
def method(boku, val):
  boku.field = val

class A:
  def __init__(self):
    self.field = 3
  def test(self):
    print self.field

class B:
  pass

class C:
  def __init__(self):
    self.field = 7

b = B()
B.test = A.__dict__['test']
B.method = method
b.method(12)
b.test()
A.__dict__['test'](C())
В вашем листинге самая ценная для меня вот эта строка:
A.__dict__['test'](C())

Никак не ожидал, что обращение через словарь класса даст разницу.

Вы решили одну мою проблему, от души спасибо. Даже плюсик вам в карму.

Но у меня тогда второй вопрос: может вы знаете, чем вызвано снятие этого ограничения в третьем питоне?

Считаю важным упомянуть о существовании lombok, который существенно сократит объёмы java классов вроде приведенных в статье.

Отличная статья, давно хочу подтянуть питон. Жаль, что в статью не включены такие разделы как generic (дженерики) и FP (элементы функционального программирования).

дженерики и фп — неочевидные и неоднозначные вещи, им полноценная статья нужна — тем более в контексте сравнения реализации и подходов в Java и Python
Не претензия к автору перевода, но автор статьи как-то совсем забыл про реализации методов по-умолчанию в интерфейсах Java… в его примерах это позволило бы не дублировать имплементацию у потомков.
В современном Python статическая типизация имеет всё больше места (mypy и пр.). И вообще это очень нужный инструмент для QA, необходимый во всём, что больше наколеночного скрипта. Как и скрытие деталей через модификаторы доступа, что, как мне показалось, преподносится как недостаток Java. Нет, это специально внедрённая фича, которая отсутствует в Python, возможно, по идеологическим соображениям (обычно что-то говорится про взрослых людей и не говорится про когнитивную нагрузку).
Имя файлаИмя модуля, содержащего класс (без расширения .py)

В Python какая-то странная модульность, которой я никак не могу проникнуться. Такое ощущение, что язык подталкивает сваливать по нескольку классов в один файл. В типичной индустриальной разработке на классах и их зависимостях получается лишняя сущность. При типизации может получаться циклический импорт без особых архитектурных проблем, так как типы — члены модулей, переменные, а не метаданные, и при использовании типа нужно выполнять содержащий его модуль (частично пофиксили в Python 4 через специальное состояние при статическом анализе, но выглядит некрасиво).
На 2-й и 3-й строчках мы определили два объекта Car: my_car и my_other_car.
Сначала свойство wheels у обоих объектов равно нулю. На 16-й строке мы установили переменную класса: car.Car.wheels = 4, у обоих объектов теперь по 4 колеса. Однако, затем когда на 24-й строке мы меняем свойство объекта my_car.wheels = 5, свойство второго объекта остается нетронутым.

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

class X(object):
    mutable = []

x1 = X()
x2 = X()

print x1.mutable # -> []
print x2.mutable # -> []

x1.mutable.append(1)

print x1.mutable # -> [1]
print x2.mutable # -> [1]


То есть в примере нужно как-то пояснить, что он безопасен только в случае с иммутабельными полями
Sign up to leave a comment.

Articles