如何在每次与类对象交互时更新类对象的属性?



例如,我有一个类:

from datetime import datetime
class Book:
def __init__(self, contents):
self.last_accessed = datetime.now()
self.content = contents

def add_content(self, addition):
self.content += str(addition)

def replace_content(self, replacement):
self.content = replacement

def read_content(self):
return self.content

我希望这个类能够记录上次访问本书的时间,例如:

Mybook = Book("Hello")  # Last accessed = datetime.now()
Mybook.add_content(" World")  # Last accessed = datetime.now(), which should be later than the previous datetime.now()
Mybook.read_content() # Last accessed should be later than when I added " World" to Mybook.content

如何使每次对 Mybook 进行更改时Mybook.last_accessed更改?

提前谢谢。

from datetime import datetime
class Book:
def __init__(self, contents):
self.__update_datetime()
self.content = contents
def __update_datetime(self):
self.last_accessed = datetime.now()
def add_content(self, addition):
self.content += str(addition)
self.__update_datetime()

def replace_content(self, replacement):
self.content = replacement
self.__update_datetime()

def read_content(self):
self.__update_datetime()
return self.content

Mybook = Book("Hello")
print(Mybook.last_accessed) # 2020-07-03 10:17:25.596847
Mybook.add_content(" World")
print(Mybook.last_accessed) # 2020-07-03 10:17:25.596905
Mybook.read_content()
print(Mybook.last_accessed) # 2020-07-03 10:17:25.596917

一个优雅的解决方案可能是利用装饰器。

以下函数可以用作装饰器,因为它是一个将一个函数作为单个参数并返回另一个函数的函数。

def set_time(func):
@functools.wraps(func)
def wrapper_set_time(self, *args, **kwargs):
self.last_accessed = datetime.now()
return func(self, *args, **kwargs)
return wrapper_set_time

这允许在调用装饰函数之前和/或之后做一些事情。

在您的特定情况下,修饰的函数将在执行计算之前自动执行self.last_accessed = datetime.now()

以下是您装饰Book类方法的方式:

class Book:
# Don't use @set_time for linters
def __init__(self, contents):
self.last_accessed = datetime.now()
self.content = contents
@set_time
def add_content(self, addition):
self.content += str(addition)
@set_time
def replace_content(self, replacement):
self.content = replacement
@set_time
def read_content(self):
return self.content

您会看到,在方法定义之前添加@set_time只是成本。

请注意,我们不是在装饰__init__方法,这只是为了让 linters 不要抱怨通过不隐藏其创建来访问类实例的.last_accessed属性。

这就是结果:

book = Book("Hello")
print(book.last_accessed)  # 2020-07-03 09:33:04.999283
book.add_content(" World")
print(book.last_accessed)  # 2020-07-03 09:33:04.999359
book.read_content()
print(book.last_accessed)  # 2020-07-03 09:33:04.999399

这是一个简单的例子,你可能希望让它更干净。

例如,装饰器只设置.last_accessed属性,但也许您希望轻松更改该名称。为此,您可以使用可以接受参数的装饰器。

请参阅 Python 装饰器上的真实 Python 入门,以获取更多见解。

最新更新