Хотя я обычно соглашаюсь с тем, что inspect
является хорошим ответом, я бы не согласился с тем, что вы не можете получить исходный код объектов, определенных в интерпретаторе. Если вы используете dill.source.getsource
из dill
, вы можете получить источник функций и лямбда, даже если они определены в интерактивном режиме. Он также может получить код для связанных или не связанных классов методов и функций, определенных в карри ... однако вы не сможете скомпилировать этот код без кода объекта-объекта.
>>> from dill.source import getsource
>>>
>>> def add(x,y):
... return x+y
...
>>> squared = lambda x:x**2
>>>
>>> print getsource(add)
def add(x,y):
return x+y
>>> print getsource(squared)
squared = lambda x:x**2
>>>
>>> class Foo(object):
... def bar(self, x):
... return x*x+x
...
>>> f = Foo()
>>>
>>> print getsource(f.bar)
def bar(self, x):
return x*x+x
>>>
но мне было интересно, смогу ли я сделать это в одной строке, используя любую функцию даты и времени, например strftime.
Насколько я могу судить, в timedelta
нет встроенного метода, который бы это делал. Если вы делаете это часто, вы можете создать свою собственную функцию, например
def strfdelta(tdelta, fmt):
d = {"days": tdelta.days}
d["hours"], rem = divmod(tdelta.seconds, 3600)
d["minutes"], d["seconds"] = divmod(rem, 60)
return fmt.format(**d)
Использование:
>>> print strfdelta(delta_obj, "{days} days {hours}:{minutes}:{seconds}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{hours} hours and {minutes} to go")
20 hours and 18 to go
Если вы хотите использовать строковый формат ближе к формату, используемому в strftime
, мы можем использовать string.Template
.
from string import Template
class DeltaTemplate(Template):
delimiter = "%"
def strfdelta(tdelta, fmt):
d = {"D": tdelta.days}
d["H"], rem = divmod(tdelta.seconds, 3600)
d["M"], d["S"] = divmod(rem, 60)
t = DeltaTemplate(fmt)
return t.substitute(**d)
Использование:
>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
20 hours and 18 to go
Значение totalSeconds отображается как 13374 вместо 99774. т.е. игнорирование значения «день».
Обратите внимание, что в приведенном выше примере вы можете использовать timedelta.days
для получения значения «день».
В качестве альтернативы, начиная с Python 2.7, timedelta имеет метод total_seconds () , который возвращает общее количество секунд, содержащихся в продолжительности.
В Python2.7 или новее вы можете использовать метод total_seconds :
import datetime as dt
turnaround = dt.timedelta(days = 1, hours = 3, minutes = 42, seconds = 54)
total_seconds = int(turnaround.total_seconds())
hours, remainder = divmod(total_seconds,60*60)
minutes, seconds = divmod(remainder,60)
print('{} hrs {} mins {} secs'.format(hours,minutes,seconds))
приводит к
27 hrs 42 mins 54 secs
В Python2.6 или старше вы Вы можете вычислить total_seconds
самостоятельно:
total_seconds = turnaround.seconds + turnaround.days*24*60*60
(более общую формулу, включая микросекунды, смотрите по ссылке выше).
Ответ Шона Чина хороший, но одна проблема с ним заключается в том, что если вы пропустите конкретный элемент в своем формате (как в его втором примере, который имеет только часы и минуты, а не дни или секунды), то это время исчезнет. из вашего результата. Вы можете изменить его, чтобы устранить эту проблему и получить более точные результаты, обрабатывая только те ключевые слова, которые фактически отображаются в строке формата.
class DeltaTemplate(Template):
delimiter = '%'
def strfdelta(tdelta, fmt):
d = {}
l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
rem = int(tdelta.total_seconds())
for k in ( 'D', 'H', 'M', 'S' ):
if "%{}".format(k) in fmt:
d[k], rem = divmod(rem, l[k])
t = DeltaTemplate(fmt)
return t.substitute(**d)
Использование:
>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
44 hours and 18 to go
Хотя форматирование жестко, поскольку вы не можете применить какие-либо строки преобразования и получить такие уродливые вещи, как это:
>>> delta_obj = timedelta(minutes=5, seconds=2)
>>> print strfdelta(delta_obj, "%H:%M:%S")
0:5:2
Однако вы можете воспользоваться тем же подходом и применить его к string.Formatter вместо string.Template и получить что-то намного лучше.
from string import Formatter
def strfdelta(tdelta, fmt):
f = Formatter()
d = {}
l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
k = map( lambda x: x[1], list(f.parse(fmt)))
rem = int(tdelta.total_seconds())
for i in ('D', 'H', 'M', 'S'):
if i in k and i in l.keys():
d[i], rem = divmod(rem, l[i])
return f.format(fmt, **d)
Использование:
>>> delta_obj = timedelta(days=1, hours=20, minutes=18, seconds=12)
>>> print strfdelta(delta_obj, "{D} days {H}:{M}:{S}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{H} hours and {M} to go")
44 hours and 18 to go
>>> delta_obj = timedelta(minutes=5, seconds=2)
>>> print strfdelta(delta_obj, "{H:02}h{M:02}m{S:02}s")
00h05m02s
>>> print strfdelta(delta_obj, "{H:02}:{M:02}:{S:02}")
00:05:02
Вы можете использовать модуль dateutil, который имеет более дружественный объект относительной дельты.
import dateutil
import datetime
alpha = datetime.datetime(2012, 1, 16, 6, 0)
beta = datetime.datetime(2012, 1, 18, 10, 42, 57, 230301)
delta = dateutil.relativedelta(beta, alpha)
это дает вам объектную дельту, которая выглядит как
>>> delta
relativedelta(days=+2, hours=+4, minutes=+42, seconds=+57, microseconds=+230301)
Затем вы можете сделать
print('turnaround %i hrs %i mins %i secs' % (delta.days * 24 + delta.hours, delta.minutes, delta.seconds)
)
Небольшой вариант ответа Шона Чина , который также затрагивает последующую проблему , поднятую mpouncett - накладывает часы , минуты и секунды с ведущими нулями, чтобы все 3 элемента использовали 2 места (более соответствует спецификации для этих полей в strftime ):
from string import Template
class DeltaTemplate(Template):
delimiter = "%"
def strfdelta(tdelta, fmt):
d = {"D": tdelta.days}
hours, rem = divmod(tdelta.seconds, 3600)
minutes, seconds = divmod(rem, 60)
d["H"] = '{:02d}'.format(hours)
d["M"] = '{:02d}'.format(minutes)
d["S"] = '{:02d}'.format(seconds)
t = DeltaTemplate(fmt)
return t.substitute(**d)
Вот тест некоторые выборочные значения:
from datetime import timedelta
for seconds in [0, 1, 59, 60, 61, 3599, 3600, 3601]:
print strfdelta(timedelta(0, seconds), '%H:%M:%S')
А вот и вывод:
00:00:00
00:00:01
00:00:59
00:01:00
00:01:01
00:59:59
01:00:00
01:00:01
def to_time(seconds):
delta = datetime.timedelta(seconds=seconds)
return str(delta.days) + 'd ' + (datetime.datetime.utcfromtimestamp(0) + delta).strftime('%H:%M')
Вышеуказанные ответы, по-видимому, не обрабатывают отрицательных значений временной шкалы (как, например, получается из pytz для часовых поясов, «оставленных» от UTC). Как указано в документации , объекты timedelta нормализованы, а отрицательная timedelta представлена отрицательным атрибутом экземпляра day
. Из документации:
Обратите внимание, что нормализация отрицательных значений может сначала удивить.
и
Строковые представления объектов timedelta нормализуются аналогично их внутреннему представлению. Это приводит к несколько необычным результатам для отрицательных timedeltas.
Например:
>>> td = timedelta(seconds=-30)
>>> str(td)
'-1 day, 23:59:30'
>>> repr(td)
'datetime.timedelta(-1, 86370)'
Учитывая этот пример timedelta, оба принятого ответа Шона Чина и ответа Гумпшена возвращают '23:59:30'
, и ответ mpounsett '-1:59:30'
.
Я думаю, что для того, чтобы печатать как отрицательные, так и положительные временные интервалы более читабельным образом, нам нужно явно обработать знак и абсолютное значение объекта часового пояса: строковое представление:
>>> strfdelta(td, "%s%H:%M:%S") # Note that %s refers to the timedelta’s sign.
'-00:00:30'
>>> strfdelta(timedelta(days=-1), "%s%D %H:%M:%S")
'-1 00:00:00'
>>> strfdelta(timedelta(days=-1, minutes=5), "%s%D %H:%M:%S")
'-0 23:55:00'
>>> strfdelta(timedelta(days=-1, minutes=-5), "%s%D %H:%M:%S")
'-1 00:05:00'
… или в более практическом контексте часовых поясов:
>>> import pytz
>>> import datetime
>>> td = pytz.timezone("Canada/Newfoundland").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(-1, 77400)
>>> strfdelta(td, fmt="%s%H:%M")
'-02:30'
>>> td = pytz.timezone("Australia/Eucla").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(0, 31500)
>>> strfdelta(td, fmt="%s%H:%M")
'+08:45'