проверки работоспособности в свойствах python частично - PullRequest
4 голосов
/ 25 октября 2011

Я новичок в python и мне нужна помощь.Я создал несколько классов со свойствами, чтобы я не мог передавать бессмысленные аргументы.

Так, например, у меня есть этот класс

class match(object):
     __teams=(None,None)

     def setTeams(self,tms):
          if type(tms) != type(list()) and type(tms) != type(tuple()):
               raise Exception("Teams must be a list of length 2")
          if len(tms) != 2:
               raise Exception("Teams must be a list of length 2")
          if (type(tms[0])==type(str()) or (type(tms[0])==type(unicode()))) \
          and (type(tms[1])==type(str()) or type(tms[1])==type(unicode())):
               self.__teams=tms
          else:
               raise Exception("Both teams must be strings")
          return

      teams=property(getTeams,setTeams)

Если я напишу

match1=match()
match1.teams=(2,4)

Я получаю исключение, как и должно, но

match1.teams[0]=5

не вызывает исключение и пропускает число 5. Имейте в виду, что это не весь класс, я просто записал только то, что относительнона мой вопрос, поэтому предположим, что код ведет себя так, как я описываю.

Я полагаю, это потому, что все передается по ссылке в python, но я должен быть осторожен, чтобы не назначать бессмысленные данные моим объектам, что противоречит целиобладать свойствами в первую очередь.

Итак, есть ли способ исправить это, кроме того, что я не использую списки, или мне нужно научиться жить с этим?

Ответы [ 3 ]

5 голосов
/ 25 октября 2011

Эта ошибка не из-за того, что вы провалили какую-то проверку типов.

Если вы неверно представили свой код (он, очевидно, отредактирован, поскольку то, что вы опубликовали, не будет работать правильно), это происходит потому, что match1.teams[0]вызывает вашу getTeams функцию, а не setTeams функцию.Чтобы убедиться в этом, попробуйте это упражнение:

class match(object):
    __teams=(None,None)
    def setTeams(self,tms):
        print "in set"
        self.__teams = tms
    def getTeams(self):
        print "in get"
        return self.__teams
    teams=property(getTeams,setTeams)

Когда я попробую это, я получу следующее:

>>> match1 = match()
>>> match1.teams[0]=5
in get
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> match1.teams = ["team1","team2"]
in set
>>> match1.teams[0]=5
in get
4 голосов
/ 25 октября 2011

Python и проверки типов не идут вместе.Учись жить с этим.Это работа любого, кто использует код для передачи правильных типов.Документируйте, чего ожидает ваш код, но не проверяйте это явно.

Существуют и другие коллекции, кроме списков и кортежей.Почему вы запрещаете, скажем, namedtuple ?Python - это динамический язык, не боритесь с ним, выписывая проверки типов.

Посмотрите EAFP в глоссарии Python.Не пытайтесь предвидеть ошибки;иметь дело с ними так, как они происходят.


Разумная вещь, которую вы могли бы сделать вместо проверки типов, - это преобразование в список:

self.__teams = list(tms)

Несовместимые со списком типы приведут к исключению длябыть поднятым на этой линии, и теперь вы можете быть уверены, что имеете дело со списком.(Разумеется, это не помешает кому-либо назначить в строку не-строки).* isinstance вместо сравнения type().Это также поймает подклассы того типа, который вам необходим.И еще, попробуйте использовать самый общий базовый тип, который вы можете.Правильный способ проверки строки (Unicode или иным образом):

if isinstance(my_object, basestring):
    ....

И правильный способ проверки коллекции, подобной списку, а не просто узколобый «список или кортеж» - это:

import collections
if isinstance(my_object, collections.Sequence):
    ...

Но это было просто в стороне, а не правильным решением вашей проблемы.Не проводите проверку типа без уважительной причины.

2 голосов
/ 26 октября 2011

Одним из преимуществ property s является возможность проверки данных - иногда очень важно убедиться, что вы получите что-то очень конкретное.

В вашем случае вам необходимо выполнить одно из следующих действий:две вещи:

  • сохраните ваши teams данные в структуре, которую нельзя изменить, например, tuple или namedtuple;затем, когда данные извлекаются, они не могут быть изменены

или

  • Ваш метод get вернет копию данных, поэтому любые изменения не могут испортить вашoriginal

Первое решение (неизменяемые типы) выглядит следующим образом:

class match(object):
    __teams=(None,None)

    def setTeams(self,tms):
        "any sequence type will do, as long as length is two"
        if len(tms) != 2:
            raise TypeError(
                "Teams must be a sequence of length 2"
                )
        if not isinstance(tms[0], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        if not isinstance(tms[1], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        self.__teams = tuple(tms)

    def getTeams(self):
        return self.__teams

    teams=property(getTeams,setTeams)

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

Traceback (most recent call last):
  File "test.py", line 22, in <module>
    match1.teams[0]=5
TypeError: 'tuple' object does not support item assignment

Второе решение (возвращение копии вместо оригинала) выглядит следующим образом:

class match(object):
    __teams=(None,None)

    def setTeams(self,tms):
        "any sequence type will do, as long as length is two"
        if len(tms) != 2:
            raise TypeError(
                "Teams must be a sequence of length 2"
                )
        if not isinstance(tms[0], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                 )
        if not isinstance(tms[1], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        self.__teams = list(tms)

    def getTeams(self):
        return list(self.__teams)

    teams=property(getTeams,setTeams)

# and the code in action...
match1=match()
match1.teams=('us',u'them')

match1.teams[0]=5
print match1.teams

, что дает следующие результаты:

['us', u'them']

Как видите, измененияне вернулся в объект match.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...