1
\$\begingroup\$

I think there must be a more pythonic way to achieve the lowercase-forcing that I need to do here. The keys in my lookup (self.adjustments) are all lc, params sent in to function can be any case (data coming from third party). Also, is it objectionable to have self.adjustments used here but not passed in?

def getRevenue(self, metric, productParam, platformParam):
    product = productParam.lower()  # better way to do this?
    platform = platformParam.lower()    # better way to do this?
    # get adjustment for product.platform, multiply by metric
    if product not in self.adjustments:
        raise Exception('Unknown adsense product: {}'.format(product))
\$\endgroup\$
  • \$\begingroup\$ Perhaps someone who knows both Python and Ruby can comment if this is possible translatable or not, but in Ruby this is [productParam, platformParam].each{|e|e.downcase!} - see grab.by/FmQM \$\endgroup\$ – Devon Parsons Mar 6 '15 at 16:45
3
\$\begingroup\$

If you have many functions that have this requirement, and if all arguments should be lowercase, you can use a decorator:

def lowercase_args(fn):
    def new_fn(*args):
        args = map(str.lower, args)
        return fn(*args)
    return new_fn

You can then use this in your function definition:

@lowercase_args
def getRevenue(self, metric, product, platform):
    # get adjustment for product.platform, multiply by metric
    if product not in self.adjustments:
        raise Exception('Unknown adsense product: {}'.format(product))
\$\endgroup\$
  • 1
    \$\begingroup\$ Interesting idea! +1 I'd call it @lowercase_args though, for clarity \$\endgroup\$ – janos Mar 9 '15 at 17:45
  • 1
    \$\begingroup\$ Yeah, good point \$\endgroup\$ – L3viathan Mar 11 '15 at 22:30
4
\$\begingroup\$

If these parameters may not always be lowercase, then I don't think there's a better way.

However, if you have many callers that are guaranteed to use lowercase parameters, and it's a pity to call .lower() for those, then you could split this into 2 functions:

  • One for callers that are guaranteed to use cleaned parameters (lowercased parameters)
  • One for untrusted callers

For example:

def _get_revenue(self, metric, product, platform):
    # get adjustment for product.platform, multiply by metric
    if product not in self.adjustments:
        raise Exception('Unknown adsense product: {}'.format(product))

def get_revenue(self, metric, product, platform):
    self._get_revenue(metric, product.lower(), platform.lower())

In the examples I used snake_case naming for method names, as recommended by PEP8.

By the way it seems a bit odd that the function name starts with "get" but it doesn't return anything.

Without seeing the full code, I don't see a reason to object against the use of self.adjustments. Whether it's objectionable or not really depends on the rest of the code.

Something to object against though is the platform param which is not used by this method. Ideally it shouldn't be there at all.

\$\endgroup\$
  • \$\begingroup\$ My apologies, I only pasted the first few lines of the method. platform is used, and the function returns a float. I don't expect many callers with known clean data, so I guess I'm stuck doing lower() at the beginning. Thanks \$\endgroup\$ – user3610360 Mar 6 '15 at 15:00
3
\$\begingroup\$

Since you seem to by using this for caseless comparisons, note that casefold might be more appropriate - it depends on whether you're using Python 3 (or Python 2 with unicode) and what alphabets you expect.

Return a casefolded copy of the string. Casefolded strings may be used for caseless matching.

Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.