2015-01-03 1 views
0

Я пишу модуль для быстрого и легкого выбора времени в программе Python. Идея состоит в том, что во всем коде могут создаваться небольшие экземпляры часов. Эти часы доступны как объекты, которые можно запускать, останавливать, запускать снова и запрашивать. Любые синхронизированные часы добавляются в список модулей всех часов. По завершении программы в этом списке может быть запрошена распечатка всех часов (либо список всех часов, либо все аналогичные часы).Как получить объект синхронизации Python для сохранения соответствующей информации в области функций и декораторов

У меня много работы, но время выполнения функций по-прежнему вызывает у меня трудности. В частности, время, измеренное для функций, измеряется как 0, используя либо явные часы, либо используя декоратор, когда время, измеренное для функций 1 и 1, должно составлять ~ 3 секунды и ~ 4 секунды соответственно.

Я подозреваю, что я не сохраняю атрибут часов _startTimeTmp соответствующим образом (его можно сбросить для внутренних расчетов).

Я очень благодарен за руководство по правильному использованию таймеров. Я немного запутался в том, как его решить!

Я знаю, что код может выглядеть немного длинным, но я минимизировал его, насколько я знаю, как не затенять видение того, что я пытаюсь сделать в целом (так, t удалить критическую функциональность). Я думаю, что разумно понятно, как это работает, по крайней мере.

модуль (shijian.py):

from __future__ import division 
import os 
import time 
import uuid as uuid 
import datetime 
import inspect 
import functools 

def _main(): 
    global clocks 
    clocks = Clocks() 

def time_UTC(
    style = None 
    ): 
    return(
     style_datetime_object(
      datetimeObject = datetime.datetime.utcnow(), 
      style = style 
     ) 
    ) 

def style_datetime_object(
    datetimeObject = None, 
    style = "YYYY-MM-DDTHHMMSS" 
    ): 
    # filename safe 
    if style == "YYYY-MM-DDTHHMMSSZ": 
     return(datetimeObject.strftime('%Y-%m-%dT%H%M%SZ')) 
    # microseconds 
    elif style == "YYYY-MM-DDTHHMMSSMMMMMMZ": 
     return(datetimeObject.strftime('%Y-%m-%dT%H%M%S%fZ')) 
    # elegant 
    elif style == "YYYY-MM-DD HH:MM:SS UTC": 
     return(datetimeObject.strftime('%Y-%m-%d %H:%M:%SZ')) 
    # UNIX time in seconds with second fraction 
    elif style == "UNIX time S.SSSSSS": 
     return(
      (datetimeObject -\ 
      datetime.datetime.utcfromtimestamp(0)).total_seconds() 
     ) 
    # UNIX time in seconds rounded 
    elif style == "UNIX time S": 
     return(
      int((datetimeObject -\ 
      datetime.datetime.utcfromtimestamp(0)).total_seconds()) 
     ) 
    # filename safe 
    else: 
     return(datetimeObject.strftime('%Y-%m-%dT%H%M%SZ')) 

def UID(): 
    return(str(uuid.uuid4())) 

class Clock(object): 

    def __init__(
     self, 
     name    = None, 
     start    = True 
     ): 
     self._name   = name 
     self._start  = start # Boolean start clock on instantiation 
     self._startTime = None # internal (value to return) 
     self._startTimeTmp = None # internal (value for calculations) 
     self._stopTime  = None # internal (value to return) 
     self._updateTime = None # internal 
     # If no name is specified, generate a unique one. 
     if self._name is None: 
      self._name  = UID() 
     # If a global clock list is detected, add a clock instance to it. 
     if "clocks" in globals(): 
      clocks.add(self) 
     self.reset() 
     if self._start: 
      self.start() 

    def start(self): 
     self._startTimeTmp = datetime.datetime.utcnow() 
     self._startTime = datetime.datetime.utcnow() 

    def stop(self): 
     self._updateTime = None 
     self._startTimeTmp = None 
     self._stopTime  = datetime.datetime.utcnow() 

    # Update the clock accumulator. 
    def update(self): 
     if self._updateTime:   
      self.accumulator += (
       datetime.datetime.utcnow() - self._updateTime 
      ) 
     else: 
      self.accumulator += (
       datetime.datetime.utcnow() - self._startTimeTmp 
      ) 
     self._updateTime = datetime.datetime.utcnow() 

    def reset(self): 
     self.accumulator = datetime.timedelta(0) 
     self._startTimeTmp = None 

    # If the clock has a start time, add the difference between now and the 
    # start time to the accumulator and return the accumulation. If the clock 
    # does not have a start time, return the accumulation. 
    def elapsed(self): 
     if self._startTimeTmp: 
      self.update() 
     return(self.accumulator) 

    def name(self): 
     return(self._name) 

    def time(self): 
     return(self.elapsed().total_seconds()) 

    def startTime(self): 
     if self._startTime: 
      return(style_datetime_object(datetimeObject = self._startTime)) 
     else: 
      return("none") 

    def stopTime(self): 
     if self._stopTime: 
      return(style_datetime_object(datetimeObject = self._stopTime)) 
     else: 
      return("none") 

    def report(
     self 
     ): 
     string = "clock attribute".ljust(39)  + "value" 
     string += "\nname".ljust(40)    + self.name() 
     string += "\ntime start (s)".ljust(40) + self.startTime() 
     string += "\ntime stop (s)".ljust(40) + self.stopTime() 
     string += "\ntime elapsed (s)".ljust(40) + str(self.time()) 
     string += "\n" 
     return(string) 

    def printout(self): 
     print(self.report()) 

def timer(function): 

    #@functools.wraps(function) 
    def decoration(
     *args, 
     **kwargs 
     ): 
     arguments = inspect.getcallargs(function, *args, **kwargs) 
     clock  = Clock(name = function.__name__) 
     result = function(*args, **kwargs) 
     clock.stop() 

    return(decoration) 

class Clocks(object): 

    def __init__(
     self 
     ): 
     self._listOfClocks  = [] 
     self._defaultReportStyle = "statistics" 

    def add(
     self, 
     clock 
     ): 
     self._listOfClocks.append(clock) 

    def report(
     self, 
     style = None 
     ): 
     if style is None: 
      style = self._defaultReportStyle 
     if self._listOfClocks != []: 
      if style == "statistics": 
       # Create a dictionary of clock types with corresponding lists of 
       # times for all instances. 
       dictionaryOfClockTypes = {} 
       # Get the names of all clocks and add them to the dictionary. 
       for clock in self._listOfClocks: 
        dictionaryOfClockTypes[clock.name()] = [] 
       # Record the values of all clocks for their respective names in 
       # the dictionary. 
       for clock in self._listOfClocks: 
        dictionaryOfClockTypes[clock.name()].append(clock.time()) 
       # Create a report, calculating the average value for each clock 
       # type. 
       string = "clock type".ljust(39) + "mean time (s)" 
       for name, values in dictionaryOfClockTypes.iteritems(): 
        string += "\n" +\ 
           str(name).ljust(39) + str(sum(values)/len(values)) 
       string += "\n" 
      elif style == "full": 
       # Create a report, listing the values of all clocks. 
       string = "clock".ljust(39) + "time (s)" 
       for clock in self._listOfClocks: 
        string += "\n" +\ 
           str(clock.name()).ljust(39) + str(clock.time()) 
       string += "\n" 
     else: 
      string = "no clocks" 
     return(string) 

    def printout(
     self, 
     style = None 
     ): 
     if style is None: 
      style = self._defaultReportStyle 
     print(self.report(style = style)) 

_main() 

Основной пример кода (examples.py):

import shijian 
import time 
import inspect 

def main(): 

    print("create clock alpha") 
    alpha = shijian.Clock(name = "alpha") 
    print("clock alpha start time: {time}".format(time = alpha.startTime())) 
    print("sleep 2 seconds") 
    time.sleep(2) 
    print("clock alpha current time (s): {time}".format(time = alpha.time())) 

    print("\ncreate clock beta") 
    beta = shijian.Clock(name = "beta") 
    print("clock beta start time: {time}".format(time = beta.startTime())) 
    print("clock beta stop time: {time}".format(time = beta.stopTime())) 
    print("sleep 2 seconds") 
    time.sleep(2) 
    print("clock beta current time (s): {time}".format(time = beta.time())) 
    print("stop clock beta") 
    beta.stop() 
    print("clock beta start time: {time}".format(time = beta.startTime())) 
    print("clock beta stop time: {time}".format(time = beta.stopTime())) 
    print("sleep 2 seconds") 
    time.sleep(2) 
    print("clock beta start time: {time}".format(time = beta.startTime())) 
    print("clock beta stop time: {time}".format(time = beta.stopTime())) 
    print("clock beta current time (s): {time}".format(time = beta.time())) 

    print("\nclock beta printout:\n") 
    beta.printout() 

    print("create two gamma clocks") 
    gamma = shijian.Clock(name = "gamma") 
    gamma = shijian.Clock(name = "gamma") 
    print("sleep 2 seconds") 
    time.sleep(2) 

    print("\ncreate two unnamed clocks") 
    delta = shijian.Clock() 
    epsilon = shijian.Clock() 
    print("sleep 2 seconds") 
    time.sleep(2) 

    print("\nrun function 1 (which is timed using internal clocks)") 
    function1() 

    print("\nrun function 2 (which is timed using a decorator)") 
    function2() 

    print("\nclocks full printout:\n") 
    shijian.clocks.printout(style = "full") 

    print("clocks statistics printout:\n") 
    shijian.clocks.printout() 

def function1(): 
    functionName = inspect.stack()[0][3] 
    clock = shijian.Clock(name = functionName) 
    print("initiate {functionName}".format(functionName = functionName)) 
    time.sleep(3) 
    print("terminate {functionName}".format(functionName = functionName)) 
    clock.stop() 

@shijian.timer 
def function2(): 
    functionName = inspect.stack()[0][3] 
    print("initiate {functionName}".format(functionName = functionName)) 
    time.sleep(4) 
    print("terminate {functionName}".format(functionName = functionName)) 

if __name__ == '__main__': 
    main() 

выходного терминала Пример:

create clock alpha 
clock alpha start time: 2015-01-03T090124Z 
sleep 2 seconds 
clock alpha current time (s): 2.000887 

create clock beta 
clock beta start time: 2015-01-03T090126Z 
clock beta stop time: none 
sleep 2 seconds 
clock beta current time (s): 2.002123 
stop clock beta 
clock beta start time: 2015-01-03T090126Z 
clock beta stop time: 2015-01-03T090128Z 
sleep 2 seconds 
clock beta start time: 2015-01-03T090126Z 
clock beta stop time: 2015-01-03T090128Z 
clock beta current time (s): 2.002123 

clock beta printout: 

clock attribute      value 
name         beta 
time start (s)       2015-01-03T090126Z 
time stop (s)       2015-01-03T090128Z 
time elapsed (s)      2.002123 

create two gamma clocks 
sleep 2 seconds 

create two unnamed clocks 
sleep 2 seconds 

run function 1 (which is timed using internal clocks) 
initiate function1 
terminate function1 

run function 2 (which is timed using a decorator) 
initiate function2 
terminate function2 

clocks full printout: 

clock         time (s) 
alpha         17.023659 
beta         2.002123 
gamma         11.018138 
gamma         11.018138 
1919f9de-85ce-48c9-b1c8-5164f3a2633e 9.017148 
d24c818c-f4e6-48d0-ad72-f050a5cf86d3 9.017027 
function1        0.0 
function2        0.0 

clocks statistics printout: 

clock type        mean time (s) 
function1        0.0 
function2        0.0 
1919f9de-85ce-48c9-b1c8-5164f3a2633e 9.017283 
beta         2.002123 
alpha         17.023834 
d24c818c-f4e6-48d0-ad72-f050a5cf86d3 9.017163 
gamma         11.0182835 
+2

Я бы порекомендовал вам взглянуть на [руководство по стилю Python] (https://www.python.org/dev/peps/pep-0008/). – jonrsharpe

+0

Было ли что-нибудь, что вы видели, что было вопиюще неправильно? Я знаю, что я запускаю функции немного необычно, а использование новой строки делает вещи немного странными (например, для математики), но это касается ограничений ширины линии. – d3pd

+1

'pylint' предоставляет 102 сообщения для' shijian.py' (включая одну ошибку в Python 3, где 'dict.iteritems' не существует) и 29 для' examples.py'. Они не влияют на функциональность (в 2.x), но если вы хотите, чтобы другие разработчики Python читали и использовали ваш код, это выглядело так, как будто Python станет хорошим началом. – jonrsharpe

ответ

1

Clock не получает update d если есть stop педаль. Минимальное исправление:

У вас есть три другие ошибки:

  • Вы должны проверить None идентичностью (if foo is not None) не truthiness (if foo), чтобы избежать проблем с False -y значений, которые Арен 't None;
  • shijian.timer не return result, так что, хотя время будет работать, вы сломаете любой код, ожидающий возврата от украшенной функции; и
  • Если вы хотите, чтобы код работал в Python 2 и 3, вы не можете использовать dict.iteritems, которого нет в последнем. Если вы только хотите, чтобы он работал в Python 2, либо from __future__ import print_function, либо используйте print whatever, а не print(whatever).

Кроме того, ваш код не совсем соответствует the style guide (или, что еще хуже, даже внутренне непротиворечивым - сравнить определение Clock.start с тем, что из Clock.report, например).

Существует также место для улучшения дизайна и функциональности (например,Clock.name может быть @property, и я бы отделил печать таблицы от генерации результатов). Вам необходимо рассмотреть вопрос о предоставлении вашего кода для Code Review, как только у вас есть:

  • завершено;
  • проверено; и
  • стиль-гид-complianced это

(вы можете найти с помощью pylint полезно для последнего).

Наконец, я предполагаю, что вы делаете это для учебных целей, а не потому, что вам нужна функциональность, как Python has its own profilers.

+1

Да! Обновление остановки часов было тем, что мне не хватало. Это хорошо видно. Большое вам спасибо за ваше руководство по этому поводу и за дополнительную помощь с декоратором, написав для Python 3 и написав больше кода Pythonic. Некоторые из моего кода здесь не блестящие, потому что они не закончены, а некоторые из них, потому что я все еще участвую. Благодарим также за ваши предложения относительно экспертной оценки кода и профилировщиков (с которыми я не знаком - этот термин для меня не знаком). Я расскажу об этом. :) – d3pd

 Смежные вопросы

  • Нет связанных вопросов^_^