2011-07-01 2 views
9

У меня есть объект, который должен иметь около 4-5 значений, переданных ему. Для иллюстрации:Инициализация переменных объекта - подход Java, подход Python?

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

    [... methods ...] 

Прямо сейчас, как использовать Swoosh является:

swoosh = Swoosh() 
swoosh.set_spam('Spam!') 
swoosh.set_eggs('Eggs!') 
swoosh.set_swallow('Swallow!') 
swoosh.set_coconut('Migrated.') 

У меня возникли сомнения, является ли это Pythonic или это слишком большое влияние Java. Или это просто необходимо? Кроме того, в случае, если вам интересно, почему я использую сеттеры вместо простого доступа к объектным переменным, необходимо выполнить некоторую базовую проверку, следовательно, методы set_.

Я думаю, я мог бы предоставить другой способ для инициализации Swoosh - обеспечить __init__(), что бы принять dict/list?

В любом случае, я просто ищу помощь/совет от кого-то более опытного с этим материалом.

Заранее благодарим за любой ввод.

+0

Почему так много людей в настоящее время пишут 'class SomeThing():' если пустые parens служат ab без цели? Или это слишком тяжелая работа, чтобы вставить «объект» между ними? – pillmuncher

ответ

15

Во-первых, вы используете классы старого стиля. Вы действительно, действительно следует использовать new style classes that inherit from object:

class Swoosh(object): 

Определение __init__ метод, который принимает аргументы, безусловно, Pythonic способ делать вещи:

def __init__(self,spam,eggs,swallow,coconut): 
    self.spam = spam 
    self.eggs = eggs 
    self.swallow = swallow 
    self.coconut = coconut 

Это позволит вам сделать:

s = Swoosh('Spam!','Eggs','Swallow','Migrated') 

Как и любая другая функция Python, метод __init__ может иметь defau lt для аргументов, например.

def __init__(self,spam,eggs,swallow,coconut='Migrated.'): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

Если вы хотите проверить атрибуты они установлены, вы должны использовать стандартные property attributes вместо того, чтобы создавать свои собственные сеттер. Если вы сделаете это так, вы можете использовать myobject.spam в своем коде, как с обычным атрибутом, но ваш метод setter все еще запущен.

Например:

@property 
def spam(self): 
    """I'm the 'spam' property.""" 
    return self._spam 

@spam.setter 
def spam(self, value): 
    if not value.endswith("!"): 
     raise ValueError("spam must end with !") 
    # Store the value in "private" _spam attribute 
    self._spam = value 

@spam.deleter 
def spam(self): 
    del self._spam 

Примечание: property будет не работать, если вы не используете классы нового стиля, как описано выше.

В вашем примере у вас есть:

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

Это часто представляется как быстрый способ установки по умолчанию для атрибутов объекта. Это нормально, но вам нужно понять, что на самом деле происходит. Что происходит, так это то, что вы устанавливаете атрибуты в классе . Если у объекта нет атрибута, Python будет искать, определено ли оно в классе и возвращает значение оттуда (поскольку это то, что вы хотите для методов).

Если вы хотите установить значения по умолчанию для атрибутов объекта, вам гораздо лучше установить значения по умолчанию для аргументов в __init__, как описано выше, вместо использования атрибутов class.

+1

+1 для новых классов стилей и предупреждения об атрибутах класса и экземпляра! –

+0

очень хороший ответ –

1

Функция __init__() - это то, что вы хотите использовать для установки значений при первом создании объекта.

Например.

class Swoosh: 
    __init__(self, arg1, arg2, arg3): 
     self.arg1 = arg1 
     self.arg2 = arg2 
     self.arg3 = arg3 
10

Прежде всего, это:

class Swoosh(): 
    spam = '' 
    eggs = '' 
    swallow = '' 
    coconut = '' 

наборы класса атрибуты spam, eggs и т.д. Ваш метод set_spam затем предположительно идти вперед и создать объект атрибуты одного и того же имени, скрыть атрибуты класса. Другими словами, определение этих атрибутов не имеет никакого эффекта и просто путает вещи.

Я хотел бы сделать это так, если все переменные являются обязательными:

class Swoosh(): 
    def __init__(self, spam="", eggs="", swallow="", coconut=""): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

Затем вы можете создавать объекты, как это:

o1 = Swoosh(eggs="Eggs!", coconut="Carried by the husk") 

Если, скажем, спам и яйца являются обязательными, затем заменить на

def __init__(self, spam, eggs, swallow="", coconut=""): 

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

def get_spam(self): 
     return self._spam 
    def set_spam(self, value): 
     self._spam = " ".join([str(value)] * 5) 
    spam = property(get_spam, set_spam) 

С учетом указанных выше изменений, это:

o2 = Swoosh(eggs="yes", spam="spam") 
print o2.spam 

отпечатки

spam spam spam spam spam 

Примечание: Как Дэйв Уэбб отмечает в своем ответе, что вам нужно создать подкласс object для свойства, чтобы работать, если вы не используете ру thon 3.0+, и в этом случае классы неявно подкласса object.Oh, и do следовать за ссылкой Sean Vieira на Python не Java статья. Это обязательное чтение.

3

Для инициализации значений Swoosh у вас есть несколько вариантов:

Во-первых, конструктор арг:

class Swoosh(object): 
    def __init__(self, spam, eggs, swallow, coconut): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

А затем создании экземпляра вашего obejct так:

swoosh = Swoosh("spam", "eggs", "swallow", "coconut") 

Если вам нужно больше контроля по пути вы получаете/устанавливаете значения, вы можете использовать метод property.

class Swoosh(): 
    def __init__(self, spam, eggs, swallow, coconut): 
     self.spam = spam 
     self.eggs = eggs 
     self.swallow = swallow 
     self.coconut = coconut 

    def set_spam(self, value): 
    #do verification stuff 
    self._spam = value 

    def get_spam(self): 
    #do what you want/need before get the value 
    return self._spam 

    spam = property(get_spam, set_spam) 

И потом, каждый вызов, как swoosh.spam = spam_value будет вызывать метод set_spam и foo = swoosh.spam будет вызывать метод get_spam.

4

Базовая проверка может быть выполнена путем переопределения соответствующего get and set methods on the class (если проверка должна быть выполнена во всех случаях) или путем изменения конкретного свойства с помощью встроенного property. Помните, Python is not Java (конечно, Java is not Python, either).

А как вы хотите, чтобы сделать ваше создание класса, у вас есть несколько вариантов:

1) Используйте __init__ метод с ключевым словом аргом, чтобы позволить людям обеспечить как много или как мало, как они хотят, чтобы ваш конструктор :

class Swoosh(object): # Get new-object goodness 
    def __init__(self, spam='', eggs='', swallow='', coconut=''): 
     # We are going to be using properties in this example 
     self._spam = spam 
     self._eggs = eggs 
     self._swallow = swallow 
     self._coconut = coconut 

2) Продолжайте делать вещи так, как вы, но обновить атрибуты класса, чтобы быть экземпляром атрибуты:

class Swoosh(object): # Get new-object goodness 
    def __init__(self): 
     self.spam = '' 
     self.eggs = '' 
     self.swallow = '' 
     self.coconut = '' 

То, как йо u делает это в настоящее время, каждый экземпляр Swoosh использует те же значения для этих переменных, и изменение значения spam на Swoosh изменит его для каждого экземпляра Swoosh, который не настроил атрибут экземпляра с тем же именем (Скорее всего, это не то, что вы хотите.)

В любом случае вы должны изучить удаление геттеров и сеттеров и их замену свойствами (когда вы это сделаете, конечно, будет зависеть от того, насколько общедоступным и широко используется этот API) :

# Inside class Swoosh's definition 
@property 
def spam(self): 
    return self._spam 
@spam.setter 
def spam(self, value): 
    # Validate that it's really SPAM, not WHAM! 
    # And only then replace the underlying value 
    self._spam = value 
@spam.deleter 
def spam(self): 
    del self._spam 
# Rinse and repeat for other properties that need access control 
+0

+1 для Python это не ссылка Java. Это замечательно! –

+0

'Как вы делаете это сейчас, каждый экземпляр Swoosh имеет одинаковые значения для этих переменных и изменение значения спама в одном экземпляре изменит его для каждого экземпляра спама (что, вероятно, не так, как вы хотите). 'Это неверно – Dikei

+0

@Dikei - совершенно правильно - обновлено до более правильного" изменения значения 'spam' на' Swoosh' изменит его для каждого экземпляра 'Swoosh', который не настроил атрибут экземпляра с тем же имя". Спасибо за улов! –

Смежные вопросы