2009-11-04 2 views
0

У меня есть класс модели с методами getter и setter, а также случайные статические методы. Я хотел бы обеспечить использование строк unicode в качестве аргументов для конкретных методов, и использование декораторов было первой моей идеей. Теперь у меня есть что-то вроде этого:Как обеспечить применение аргументов unicode для методов?

import types 

class require_unicode(object): 

    def __init__(self, function): 
     self.f = function 

    def __call__(self, string): 
     if not isinstance(string, types.UnicodeType): 
      raise ValueError('String is not unicode') 
     return self.f(string) 

class Foo(object): 

    something = 'bar' 

    @staticmethod 
    @require_unicode 
    def do_another(self, string): 
     return ' '.join(['baz', string]) 

    @require_unicode 
    def set_something(self, string): 
     self.something = string 

foo = Foo() 
foo.set_something('ValueError is raised') 
foo.set_something(u'argument count error') 
foo.do_another('ValueError is raised') 
foo.do_another(u'argument count error') 

В приведенном выше коде метод вызова внутри отделочника __call__ терпит неудачу из-за неправильного подсчета аргументов (потому что «Foo» объект исх отсутствует?). Прежде чем сделать что-то глупое, я хотел спросить вас, ребята. Как это должно быть сделано?

ответ

1

Я думаю, ваша проблема связана с декоратором @staticmethod, а не с вашим декоратором require_unicode. Staticmethods, в отличие от методов класса, не получают ссылку на класс в качестве первого аргумента, поэтому ваша подпись аргумента неверна.

Вы должны либо изменить do_another как @classmethod, либо удалить self из аргументов.

EDIT: и, заметьте, - @ classmethod декорированных методов получить класс в качестве первого аргумента, в то время как методы экземпляра получить ссылку на экземпляра класс (сам). Поэтому неплохо назвать первый аргумент classmethod «cls» или что-то, а не «я», чтобы он никого не смутил.

0

Я бы подумал, что это было бесстрашно - вы никогда не должны проверять тип своих аргументов, но вместо этого проверяйте, что у них есть необходимые методы и атрибуты. Самый простой способ сделать это - предположить, что они есть и получить исключение в противном случае, но я думаю, вы могли бы сделать и getattr. Просто не проверьте тип вещей.

+0

Я знаю, что это неряшливо, но предотвращение закодированных строк здесь избавит меня от многих неприятностей позже при сохранении данных в базе данных. – tuomur

+0

@eclaird: После того, как вы абсолютно положительно * потребуете * unicode, просто назовите 'unicode()' на все, что у вас есть, и назовите это хорошо. – Teddy

0

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

import types 
class Foo: 
    def set_something(self, string): 
     assert isinstance(string, types.UnicodeType), 'String is not unicode' 
     self.something = string 

Это вызовет AssertionError исключение, когда string не типа Юникода, но только тогда, когда interpretter Python запускается в режиме «deubg». Если вы запустите Python с опцией -O, утверждение будет эффективно игнорироваться интерпретатором.

+0

Абсолютно, я думал об этом тоже, но фигурные декораторы были бы более чистым способом сделать это. – tuomur

+0

Что на самом деле выглядит для вас чище? ИМО утверждение гораздо более очевидно, поскольку проверки находятся прямо там в начале метода, а не скрыты в классе, который может быть импортирован из других источников. Вы также получаете преимущество в производительности, когда assert эффективно становится NOP при запуске python с '-O'. – mhawke

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