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 — публичные поля.
Боюсь, после прочтения статьи у читателей создастся ложное представление и вместо лаконичного и в большинстве случаев подходящего
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, которые более похожи в плане синтаксиса.
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, в более старых тип немного по другому указывается, но всё равно лучше чем дефолтный способ.
так что-то похожее вроде ж из коробки можно, не?
В Python же «встроенной» ссылки на текущий объект нету, так как в Питоне методы класса — это на самом деле обычные функции, которые фактически ничего не знают про то, что они привязаны к какому-то классу. Просто Питон при вызове метода на экземпляре класса передает в функцию первым аргументом ссылку на этот объект.
Из-за такой особенности Питона, в частности, возможны всякие «грязные трюки » вроде вызова метода одного класса в контексте экземпляра совсем другого класса, что в Java в принципе невозможно (и к лучшему).
В жабе рефлексией можно получит метод/поле одного класса и потом пытаться вызвать его для объекта другого класса. Как бы велком, один вопрос — на… зачем?
один вопрос — на… зачем?Пример с таким вызовом — всего лишь способ показать фундаментальное различие между обсуждаемыми ЯП.
Если метод интерфейсный и класс его реализует то всё будет окай. Вопрос в другом. Зачем сравнивать разные языки по своей природе? Строго типизированный типа жабы с питоном. Компмлируемый со скриптовым. Естественно различия будут. Но примеры сравнивания с трамвайной ручкой это следствия, а не индикаторы различий.
в Питоне методы класса — это на самом деле обычные функции, которые фактически ничего не знают про то, что они привязаны к какому-то классу
Зачем же так подставляться? Когда надо — они кое-что знают:
myformat = "<{}>".format
print(myformat("qwe"))
Вы передали в функцию первым аргументом экземпляр класса
Если бы я сделал то, что вы мне приписываете, я бы сделал это так:
str.format("<{}>", "qwe")
Улавливаете разницу?На самом деле я обратился к экземпляру класса: поищи-ка у себя что-то по имени
format
. И он (экземпляр класса) таки нашел у себя метод с этим именем.И да: если не улавливаете — не утруждайте себя ответом.
В первом случае — это как раз-таки метод класса, который действительно является функцией и ничего не знает о том, к какому классу он прикреплён. Во-втором — это 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())
Но все равно спасибо за ответ.
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 (элементы функционального программирования).
Имя файлаИмя модуля, содержащего класс (без расширения .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]
То есть в примере нужно как-то пояснить, что он безопасен только в случае с иммутабельными полями
Объектно-ориентированное программирование в Java и Python: сходства и отличия