{"id":1443,"date":"2020-12-07T16:44:27","date_gmt":"2020-12-07T16:44:27","guid":{"rendered":"https:\/\/www.pyxll.com\/blog\/?p=1443"},"modified":"2021-10-29T12:59:34","modified_gmt":"2021-10-29T12:59:34","slug":"single-shot-functions","status":"publish","type":"post","link":"https:\/\/www.pyxll.com\/blog\/single-shot-functions\/","title":{"rendered":"&#8220;Single Shot&#8221; Excel Worksheet Functions with Python"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">What is a &#8220;single shot&#8221; function?<\/h2>\n\n\n\n<p>Excel worksheet functions recalculate automatically whenever an input changes or when the user recalcultes the workbook. This is true of all Excel worksheet functions or UDFs (User Defined Functions), including those written in Python with PyXLL. Most times this is what you want; if you calculate the sum of the numbers in a column using <a href=\"https:\/\/support.microsoft.com\/en-us\/office\/sum-function-043e1c7d-7726-4e80-8f32-07b23e057f89\" target=\"_blank\" rel=\"noreferrer noopener\">&#8220;=SUM&#8221;<\/a> then naturally you want that to update whenever one of the inputs changes.<\/p>\n\n\n\n<p>What if you want to call a function once and then fix the result so it won&#8217;t update, even if some inputs change or the user recalculates the sheet? A function that works like this is what we mean in this article by a &#8220;single shot&#8221; function. This article explains how to write such a single shot Excel worksheet function in Python using PyXLL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">An example single shot function<\/h2>\n\n\n\n<p>Imagine you wanted to insert the current time into a sheet. You might use &#8220;=NOW()&#8221;, but then the result will update each time the sheet is calculated. Let&#8217;s add a new function &#8220;timestamp&#8221; that will return the current time using Python and PyXLL<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom pyxll import xl_func\nimport datetime as dt\n\n@xl_func\ndef timestamp():\n    return dt.datetime.now()\n<\/pre><\/div>\n\n\n<p>This function is not <a href=\"http:\/\/www.decisionmodels.com\/calcsecretsi.htm\" target=\"_blank\" rel=\"noreferrer noopener\">volatile<\/a>. The returned current time and date does not update each time the sheet is calculated. However, if we fully recalculate the sheet or change an input (if the function had one!) then the function is called again, which is not what we want.<\/p>\n\n\n\n<p>To make the function a true &#8220;single shot&#8221; function where once the result is returned it becomes completely fixed we need to replace the formula with its calculated value. For that we can use <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pyxll.com\/docs\/userguide\/formatting\/index.html\" target=\"_blank\">PyXLL&#8217;s cell formatting feature<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fixing the result<\/h2>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.pyxll.com\/docs\/userguide\/formatting\/index.html\" target=\"_blank\">PyXLL&#8217;s Cell Formatting<\/a> updates the style or appearance of the range in Excel. Formatting can be applied to any Python Excel worksheet function using the <a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/udfs\/introduction.html\" target=\"_blank\" rel=\"noreferrer noopener\">@xl_func<\/a> decorator. Here we will use it to actually set the cell value to the returned value. This replaces the formula and stops the function from being called again. You can think of it as doing the same thing as &#8220;Copy\/Paste Value&#8221;, but automatically whenever you use the function. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom pyxll import Formatter, xl_func\nimport datetime as dt\n\nclass SingleShotFormatter(Formatter):\n\n    def apply(self, cell, *args, **kwargs):\n        # Setting cell.value replaces the formula\n        cell.value = cell.value\n\nsingle_shot_formatter = SingleShotFormatter()\n\n@xl_func(formatter=single_shot_formatter)\ndef timestamp():\n    return dt.datetime.now()\n<\/pre><\/div>\n\n\n<p>When the timestamp function is called from Excel the formatter is used to update the cell appearance. Our custom &#8220;SingleShotFormatter&#8221; sets the cell value to the current value. This fixes the value and removes the formula from the cell.<\/p>\n\n\n\n<p>This technique not only works for single value functions like &#8220;timestamp&#8221; above but also works for <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pyxll.com\/docs\/userguide\/udfs\/arrayfuncs.html\" target=\"_blank\">array functions<\/a>. Often an <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pyxll.com\/docs\/userguide\/macros.html\" target=\"_blank\">Excel macro<\/a> or <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pyxll.com\/docs\/userguide\/ribbon.html\" target=\"_blank\">ribbon function<\/a> is used to paste data into a Range, but using a single shot Excel function can be a good alternative!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Single shot functions are functions that only ever get calculated once. Instead of being recalculated if an input changes or the sheet is refreshed the result of a single shot function is fixed.<\/p>\n","protected":false},"author":1,"featured_media":1454,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,2],"tags":[648,647,646],"class_list":["post-1443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","category-pyxll","tag-formatting","tag-functions","tag-udfs"],"acf":[],"jetpack_featured_media_url":"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2020\/12\/single-shot-e1607359232303.jpg","jetpack_shortlink":"https:\/\/wp.me\/p7l3LP-nh","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/comments?post=1443"}],"version-history":[{"count":1,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1443\/revisions"}],"predecessor-version":[{"id":1557,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1443\/revisions\/1557"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media\/1454"}],"wp:attachment":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media?parent=1443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/categories?post=1443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/tags?post=1443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}