在python中,编写如下__init__定义是不好的形式:
class someFileType(object):
def __init__(self, path):
self.path = path
self.filename = self.getFilename()
self.client = self.getClient()
self.date = self.getDate()
self.title = self.getTitle()
self.filetype = self.getFiletype()
def getFilename(self):
'''Returns entire file name without extension'''
filename = os.path.basename(self.path)
filename = os.path.splitext(filename)
filename = filename[0]
return filename
def getClient(self):
'''Returns client name associated with file'''
client = self.filename.split()
client = client[1] # Assuming filename is formatted "date client - docTitle"
return client
Run Code Online (Sandbox Code Playgroud)
初始化变量是否调用返回字符串的函数?或者它被认为是懒惰的编码?这主要是为了救我写something.filetype的something.getFiletype(),每当我想引用该文件的某些方面.
此代码用于按客户端将文件排序到文件夹中,然后按文档类型排序,以及基于文件名中的数据进行其他操作.
Mar*_*ers 12
不,我不明白为什么那会是糟糕的形式.实际上,在创建实例时仅计算一次这些值可能是一个好主意.
您还可以使用缓存来推迟计算,直到需要property:
class SomeFileType(object):
_filename = None
_client = None
def __init__(self, path):
self.path = path
@property
def filename(self):
if self._filename is None:
filename = os.path.basename(self.path)
self._filename = os.path.splitext(filename)[0]
return self._filename
@property
def client(self):
'''Returns client name associated with file'''
if self._client is None:
client = self.filename.split()
self._client = client[1] # Assuming filename is formatted "date client - docTitle"
return self._client
Run Code Online (Sandbox Code Playgroud)
现在,访问somefiletypeinstance.client将self.filename根据需要触发计算,以及缓存自己计算的结果.
在这种特定情况下,您可能也想要制作.path一个属性; 一个用于清除缓存值的setter:
class SomeFileType(object):
_filename = None
_client = None
def __init__(self, path):
self._path = path
@property
def path(self):
return self._path
@path.setter
def path(self, value):
# clear all private instance attributes
for key in [k for k in vars(self) if k[0] == '_']:
delattr(self, key)
self._path = value
@property
def filename(self):
if self._filename is None:
filename = os.path.basename(self.path)
self._filename = os.path.splitext(filename)[0]
return self._filename
@property
def client(self):
'''Returns client name associated with file'''
if self._client is None:
client = self.filename.split()
self._client = client[1] # Assuming filename is formatted "date client - docTitle"
return self._client
Run Code Online (Sandbox Code Playgroud)
因为property基于缓存会增加一些复杂性开销,所以你需要考虑它是否真的值得你花时间; 对于您的具体,简单的例子,它可能不是.您的属性的计算成本确实非常低,除非您计划创建大量这些类,否则与必须维护按需缓存属性的心理成本相比,提前计算属性的开销可以忽略不计.
你的代码做了两件不同的事情:
a)通过将某些计算属性公开为变量而不是函数来简化类API.
b)预先计算它们的值.
第一项任务是属性的用途; 直接使用会使您的代码更简单,而不是更复杂,并且(同样重要)会使意图更清晰:
class someFileType(object):
@property
def filename(self):
return os.path.basename(self.path)
Run Code Online (Sandbox Code Playgroud)
然后var.filename,您可以编写,然后从路径动态计算文件名.
@ Martijn的解决方案增加了缓存,它还负责b部分(预计算).在你的例子中,至少,计算是便宜的,所以我认为没有任何好处.
相反,缓存或预计算会引发一致性问题.请考虑以下代码段:
something = someFileType("/home/me/document.txt")
print something.filename # prints `document`
...
something.path = "/home/me/document-v2.txt"
print something.filename # STILL prints `document` if you cache values
Run Code Online (Sandbox Code Playgroud)
最后的陈述应该打印什么?如果你缓存你的计算,你仍然会得到document而不是document-v2!除非您确定没有人会尝试更改基本变量的值,否则您需要避免缓存,或采取措施来确保一致性.最简单的方法是禁止修改path- 属性旨在执行的操作之一.
结论:使用属性来简化界面.不要缓存计算,除非出于性能原因需要.如果缓存,请采取措施确保一致性,例如将基础值设为只读.
PS.问题类似于数据库规范化(非规范化设计引发一致性问题),但在python中,您有更多资源来保持事物同步.