Питон: ** карг вместо перегрузки? - PullRequest
5 голосов
/ 05 июля 2010

У меня есть концептуальная дилемма Python.

Скажем, у меня есть класс City, который представляет город в базе данных.Объект City можно инициализировать двумя способами:

  1. Целое число (фактически, идентификатор существующего города в базе данных)
  2. Список свойств (name, country, population, ...), который сгенерирует новый город в базе данных и получит его идентификатор.

Это означает, что объект City всегда будет иметь идентификатор -либо инициализированный идентификатор, либо вновь созданный идентификатор, полученный из базы данных.

Классический подход Java перегружает конструктор - один конструктор получит один параметр int, а другойполучит множество строго типизированных параметров.

Мне не удалось найти элегантный способ сделать это в Python:

  • Я могу создать базовый класс с помощью одного метода get_city_id и извлекаем из него CityFromID и CityFromNewData, но это много усилий для обхода этого языкового пробела.
  • Использование методов класса кажется неудобным .
  • Использование конструктора с длинным списком параметров также неудобно: я бы поставили идентификатор города, и альтернативы, и проверьте в методе, что значения имеют только определенное подмножество.

Использование **kargs кажется очень не элегантным, поскольку в сигнатуре конструктора нет четкого указания требуемоговходных параметров и строк документации просто недостаточно:

class City(object):
    def __init__(self, city_id=None, *args, **kargs):
        try:
            if city_id==None:
                self.city_id=city_id
            else:
                self.city_name=kargs['name']
        except:
            error="A city object must be instanciated with a city id or with"+\
            " full city details."
            raise NameError(error)

Есть ли Pythonic, элегантное решение для перегрузки конструктора?

Adam

Ответы [ 3 ]

7 голосов
/ 05 июля 2010

Как насчет:

class City(object):
   def __init__(self, name, description, country, populations):
      self.city_name = name
      # etc.

   @classmethod
   def from_id(cls, city_id):
       # initialise from DB 

Затем вы можете сделать обычное создание объекта:

 >>> c = City('Hollowberg', '', 'Densin', 3)
 >>> c.id
 1233L

 >>> c2 = City.from_id(1233)

~~~~~~

Также вы можете проверить SQLAlchemy Elixir ) для более хороших способов сделать это

4 голосов
/ 05 июля 2010

Существует шаблон проектирования под названием Объект доступа к данным , который обычно используется в вашем случае. В соответствии с этим вы должны разделить выборку и создание объектов данных в двух классах City и CityDAO:

class City:

    def __init__(self, name, country):
        self.name = name
        self.country = country 


class CityDAO:

    def fetch(self, id):
        return query(...)

    def insert(self, city):
        query(...)
2 голосов
/ 05 июля 2010

Я думаю, что метод класса (фабрики) - лучший, потому что имя метода уже ясно указывает, что сделано. Также подойдут две отдельно стоящие функции:

def load_existing_city(id):
    ...
def create_new_city(name, population, ...):
    ...
...