я могу это сделать:Как переопределить метод __str__ класса Python при построении с аргументом?
class Person:
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
def __str__(self):
print self.firstName
bob = Person('Robert', 'Smith')
print bob
>>> Robert
Но я хочу сделать это в более общем плане, а не перекрывать __str__
для каждого класса вручную. Я пробовал использовать декораторы и метаклассы, но я смущен. Я думаю, что это должно быть возможно сделать что-то похожее на это, но я не знаю, как сделать декоратор или метакласс принять аргумент и до сих пор создать правильно инстанциируемый объект:
class strAs:
def __init__(self, prop):
self.prop = prop
def __call__(self, cls):
decoratorSelf = self
def wrapper(*args, **kwargs):
def __str__(s):
return getattr(s, decoratorSelf.prop)
c = cls(*args, **kwargs)
c.__str__ = __str__
return c
return wrapper
@strAs(prop='firstName')
class Person:
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
@strAs(prop='name')
class Dog:
def __init__(self, name):
self.name = name
bob = Person('Robert', 'Smith')
fido = Dog('Fido')
print bob
print fido
>>> Robert
Fido
Но это терпит неудачу с:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/py6495xVN", line 33, in <module>
print bob
TypeError: __str__() takes exactly 1 argument (0 given)
Я не могу понять, почему __str__()
не получает self
прошел к нему. Я заметил, что bob
экземпляр Person
класса, кажется, отсутствуют некоторые типичные методы объекта, поэтому я попытался я подклассов object
, как это (и добавлены два оператора печати):
class strAs(object):
def __init__(self, prop):
self.prop = prop
def __call__(self, cls):
decoratorSelf = self
def wrapper(*args, **kwargs):
print 'in wrapper'
def __newstr__(s):
print 'in newstr'
return getattr(s, decoratorSelf.prop)
c = cls(*args, **kwargs)
c.__str__ = __newstr__
return c
return wrapper
@strAs(prop='firstName')
class Person(object):
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
@strAs(prop='name')
class Dog(object):
def __init__(self, name):
self.name = name
bob = Person('Robert', 'Smith')
fido = Dog('Fido')
print bob
print fido
А теперь я получаю некоторый выход с __str__
по-видимому, вызывается правильно:
>>> in wrapper
in wrapper
<__main__.Person object at 0x7f179389e450>
<__main__.Dog object at 0x7f179389e510>
Но это не печатает свойство, как это должно быть, и это не кажется, даже с помощью функции __newstr__
, потому что это не печать in newstr
. Однако, если я проверю bob.__str__
, я вижу, что это действительно <function __newstr__ at 0x7f17951d78c0>
.
Мне, должно быть, недостает чего-то очевидного, но я чувствую, что это сейчас над моей головой. :/
Если ваш вопрос о том, как писать декораторов, которые принимают параметры, вы можете захотеть взглянуть на этот вопрос [] (http://stackoverflow.com/questions/5929107/python-decorators-with- параметры). – BrenBarn
Спасибо, я много искал и нашел такую информацию, но то, что я пытаюсь сделать, это украсить класс и заменить один из его методов, передав аргумент конструктору, который изменит оформленный класс. Я могу найти множество примеров декораторов функций, декораторов функций с аргументами и декораторов классов, но я не могу найти декораторов классов (то есть, применяя декораторы к классам, а не к декораторам на основе классов) с аргументами. Я уверен, что мне не хватает чего-то очевидного, но я думаю, это не очевидно для меня. – blujay
Идея такая же. Если вы прочитаете вопрос, который я связал, вы увидите ответ: «Декоратор с аргументами должен вернуть функцию, которая будет принимать функцию и вернуть другую функцию». То же самое относится к декораторам классов; это просто означает, что декоратор с аргументами должен возвращать функцию, которая возьмет класс и вернет другой класс. Другими словами, 'strAs' должен вернуть фактический декоратор. Попробуйте приспособить там ответ и задайте более конкретный вопрос, если вы не можете понять это. – BrenBarn