Как определить класс в 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)

Некоторые примечания по этому вопросу:

  1. Я заявил, что Team наследуется от object. Это делает команду "классом нового стиля"; это было рекомендовано в Python с момента его появления в Python 2.2. (В Python 3.0 и выше классы всегда "в новом стиле", даже если вы пропустите нотацию (object); но эта нотация не вредит и делает наследование явным.) Здесь обсуждение Qaru discussion классов нового стиля.

  2. Это не обязательно, но я заставил инициализатор принимать необязательные аргументы, чтобы вы могли инициализировать экземпляр в одну строку, как я делал с team и team3. Эти аргументы имеют имена, так что вы можете предоставить значения в качестве позиционных параметров (как с team) или использовать форму argument=, как я это делал с team3. Когда вы явно указываете имя аргументов, вы можете указывать аргументы в любом порядке.

  3. Если вам нужно иметь функции получения и установки, возможно, что-то для проверки, в Python вы можете объявить специальные функции метода. Вот что имел в виду Мартин против Лёвиса, когда говорил "дескрипторы свойств". В Python считается хорошей практикой просто присваивать переменным-членам и просто ссылаться на них для их извлечения, потому что вы всегда можете добавить дескрипторы свойств позже, если они вам понадобятся. (И если они вам никогда не понадобятся, тогда ваш код будет менее загроможден и вам понадобится меньше времени для написания. Бонус!)

    Вот хорошая ссылка о дескрипторах свойств: http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/

  4. На самом деле не имеет значения, указали ли вы значения как часть вызова 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 или, по крайней мере, идиома, которую вы должны освоить.