近期一个项目要写一个类,跟同学争执不下,特来请教各位大佬
import time
class SchoolDate(object):
def __init__(self, school_time):
self.weeks = 1
self.what_day = 1
self.school_time = time.strptime(school_time, "%Y-%m-%d")
def get_term(self):
timestamp = time.mktime(self.school_time)
#计算开学前周日的时间戳
first_week_timestamp=timestamp- 86400* int(time.strftime("%w",self.school_time))
now_timestamp = time.time()
self.what_day = time.strftime("%w",time.localtime(now_timestamp))
#周数 = (当前时间戳 - 开学周日的时间戳) / 7 天 +1
self.weeks = int((time.time() -first_week_timestamp)/ (86400*7)) + 1
if self.weeks < 1:
self.what_day = 1
self.weeks = 1
return self
def weeks(self):
return self.weeks
def day(self):
return self.what_day
版本 2
import time
from datetime import datetime
class SchoolDate(object):
__get = False
def __init__(self, starting_date):
"""
:param starting_date: 开学日期
"""
self.now_weeks = 1
self.what_day = 1
self.starting_date = time.strptime(starting_date, "%Y-%m-%d")
def _get_term(self):
self.__get = True
timestamp = time.mktime(self.starting_date)
# 计算开学前周日的时间戳
first_week_timestamp = timestamp - 86400 * int(time.strftime("%w", self.starting_date))
now_timestamp = time.time()
self.what_day = time.strftime("%w", time.localtime(now_timestamp))
# 周数 = (当前时间戳 - 开学周日的时间戳) / 7 天 +1
self.now_weeks = int((time.time() - first_week_timestamp) / (86400*7)) + 1
if self.weeks < 1:
self.what_day = 1
self.now_weeks = 1
@property
def weeks(self):
"""开学第几周"""
if not self.__get:
self._get_term()
return self.now_weeks
@property
def week_day(self):
"""周几"""
if not self.__get:
self._get_term()
return self.what_day
@property
def school_year(self):
"""获取当前学年"""
now = datetime.now()
if 2 <= now.month <= 7:
return "%d-%d" % ((now.year - 1), now.year)
else:
return "%d-%d" % (now.year, (now.year + 1))
初级写法,敬请吐槽!!
1
msg7086 2018-02-11 10:59:33 +08:00
school_year 这个方法只有版本 2 里有。
__get 这个只是数据缓存标志位吧。 最理想的做法大概是用非侵入式元编程来智能缓存,但是说白了,没有数据量要求,怎么写都行。更重要的是可读性可维护性,缓存什么的无所谓啦。就说版本 1,如果有一天客户说,我们流量大了要提速,让你改成版本 2,你觉得会花多久? |
2
cz5424 OP 这个类不只是做周数计算,而且我想吐槽版本 1 的一点是,必须调用 get_term 才能获取下面两个参数
@msg7086 |
4
msg7086 2018-02-11 11:08:52 +08:00
sd.get_term().weeks()?链式调用我觉得也还行。
这个类到底是做什么的你也没说啊。 |
5
cz5424 OP 调用版本一
school = shooldate().get_term() school.weeks() |
8
leavic 2018-02-11 11:17:40 +08:00
simple is better
|
9
cz5424 OP @msg7086 如果用链式,这样的缺点是每次获取都要计算一次吧,他要获取的往往并不止一个参数,也就是得到周几的时候还要知道这一周是第几周
|
10
msg7086 2018-02-11 11:31:46 +08:00
@cz5424 参考#1 最后一段内容。
没有性能要求的时候,随便你怎么写。甚至越简单越好,因为越简单的代码,越容易读懂和针对性优化。 |
11
ipwx 2018-02-11 11:51:19 +08:00
永远不要让外部调用者接触类内部的缓存策略。
第一个版版直接枪毙。 第二个版本,_get_term 命名不合理。get_XXX 一般默认不引起副作用,哪怕是私有(保护)函数。 p.s. 为啥第二个版本不初始化 now_weeks = what_day = None,通过 is None 决定是否调用 _get_term,而要一个单独的 __get 标志位? |
12
ipwx 2018-02-11 11:58:35 +08:00
我觉得楼主和你的小伙伴最好注意一下“副作用”有关的各种约定。
面向对象设计中,为了让调用更安全,函数语义上最好隔离“读取”和“写入”。换句话说,叫做 get_xxx 的,语义上应该只返回状态而不更改状态,叫做 set_xxx 的则只更改状态而不返回状态(返回 self 例外,这是链式调用)。 缓存策略是另一回事。它应该对调用者透明。换句话说,你要是不高兴现在的缓存策略,可以随时更换,而不影响接口语义。所以你第一个版本是不对的,因为调用者需要明确知道 get_term 引起一次缓存,这个接口设计是不合理的。 |
13
fxxkgw 2018-02-11 12:16:12 +08:00
第一个版本属性 weeks 和方法 weeks 难道不冲突么? SchoolDate object 加入叫 t,那 t.weeks t.weeks() 都能 OK 么?
|
16
paicha 2018-02-11 14:54:32 +08:00 via iPhone
ipwx 说的已经挺多的,结构上第二种会比较好,还有命名写法的细节可以改进。
其实没什么好争论的,Python 已经是有相当多最佳实践的例子了,可以阅读学习一些优秀开源项目代码。 |
17
hsuan 2018-02-11 15:13:28 +08:00 via Android
两个都不咋地,好的代码要做到自解释,看到就应该明白是做什么的,该怎么用。
|