Как определить класс в Python?
Довольно просто, я изучаю python, и я не могу найти ссылку, которая подскажет мне, как написать следующее:
public class Team {
private String name;
private String logo;
private int members;
public Team(){}
// getters/setters
}
Далее:
Team team = new Team();
team.setName( "Oscar" );
team.setLogo( "http://...." );
team.setMembers( 10 );
Это класс Команда со свойствами: name/logo/members
Edit
После нескольких попыток я получил следующее:
class Team:
pass
Далее
team = Team()
team.name="Oscar"
team.logo="http://..."
team.members=10
Является ли это способом python? Чувствует себя странным (исходя из строго типизированного языка, конечно)
Ответы
Ответ 1
class Team:
def __init__(self):
self.name = None
self.logo = None
self.members = 0
В Python вы обычно не записываете геттеры и сеттеры, если у вас действительно нет нетривиальной реализации для них (в этот момент вы используете дескрипторы свойств).
Ответ 2
Вот что я бы порекомендовал:
class Team(object):
def __init__(self, name=None, logo=None, members=0):
self.name = name
self.logo = logo
self.members = members
team = Team("Oscar", "http://...", 10)
team2 = Team()
team2.name = "Fred"
team3 = Team(name="Joe", members=10)
Некоторые примечания по этому вопросу:
Я заявил, что Team
наследуется от object
. Это делает команду "классом нового стиля"; это было рекомендовано в Python с момента его появления в Python 2.2. (В Python 3.0 и выше классы всегда "в новом стиле", даже если вы пропустите нотацию (object)
; но эта нотация не вредит и делает наследование явным.) Здесь обсуждение Qaru discussion классов нового стиля.
Это не обязательно, но я заставил инициализатор принимать необязательные аргументы, чтобы вы могли инициализировать экземпляр в одну строку, как я делал с team
и team3
. Эти аргументы имеют имена, так что вы можете предоставить значения в качестве позиционных параметров (как с team
) или использовать форму argument=
, как я это делал с team3
. Когда вы явно указываете имя аргументов, вы можете указывать аргументы в любом порядке.
Если вам нужно иметь функции получения и установки, возможно, что-то для проверки, в Python вы можете объявить специальные функции метода. Вот что имел в виду Мартин против Лёвиса, когда говорил "дескрипторы свойств". В Python считается хорошей практикой просто присваивать переменным-членам и просто ссылаться на них для их извлечения, потому что вы всегда можете добавить дескрипторы свойств позже, если они вам понадобятся. (И если они вам никогда не понадобятся, тогда ваш код будет менее загроможден и вам понадобится меньше времени для написания. Бонус!)
Вот хорошая ссылка о дескрипторах свойств: http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
На самом деле не имеет значения, указали ли вы значения как часть вызова Team()
или вставили ли вы их в свой экземпляр класса позже. Последний экземпляр класса, с которым вы столкнетесь, будет идентичным.
team = Team("Joe", "http://example.com", 1)
team2 = Team()
team2.name = "Joe"
team2.logo = "http://example.com"
team2.members = 1
print team.__dict__ == team2.__dict__
Выше будет напечатано True
. (Вы можете легко перегрузить оператор ==
для экземпляров Team
и заставить Python делать правильные вещи, когда вы говорите team == team2
, но это не происходит по умолчанию.)
ОБНОВЛЕНИЕ: я упустил одну вещь в ответе выше, и я хотел бы добавить это сейчас. Если вы выполняете необязательный аргумент в функции __init__()
, вам нужно быть осторожным, если вы хотите предоставить "изменяемый" в качестве необязательного аргумента.
Целые числа и строки являются "неизменяемыми". Вы никогда не можете изменить их на месте; Вместо этого Python создает новый объект и заменяет тот, который у вас был раньше.
Списки и словари являются "изменчивыми". Вы можете хранить один и тот же объект вечно, добавляя и удаляя его.
x = 3 # the name "x" is bound to an integer object with value 3
x += 1 # the name "x" is rebound to a different integer object with value 4
x = [] # the name "x" is bound to an empty list object
x.append(1) # the 1 is appended to the same list x already had
Главное, что вам нужно знать: необязательные аргументы вычисляются только один раз, когда функция компилируется. Так что, если вы передаете изменяемый в качестве необязательного аргумента в __init__()
для вашего класса, то каждый экземпляр вашего класса совместно использует один изменяемый объект. Это почти никогда не то, что вы хотите.
class K(object):
def __init__(self, lst=[]):
self.lst = lst
k0 = K()
k1 = K()
k0.lst.append(1)
print k0.lst # prints "[1]"
print k1.lst # also prints "[1]"
k1.lst.append(2)
print k0.lst # prints "[1, 2]"
Решение очень простое:
class K(object):
def __init__(self, lst=None):
if lst is None:
self.lst = [] # bind lst with a new, empty list
else:
self.lst = lst # bind lst with provided list
k0 = K()
k1 = K()
k0.lst.append(1)
print k0.lst # prints "[1]"
print k1.lst # print "[]"
Это бизнес использования значения аргумента по умолчанию None
, а затем проверки того, что аргумент, переданный is None
, квалифицируется как шаблон проектирования Python или, по крайней мере, идиома, которую вы должны освоить.