简体   繁体   中英

Smarter method of decimal to numeric conversion

Given a percent--for example, 5.43%--call its:

  • numeric form -> 5.43
  • decimal form -> 0.0543

The logic for converting between the two would be as follows:

input form      output form         operation
----------      -----------         ---------
numeric         numeric             multiply by 1.
decimal         decimal             multiply by 1.
numeric         decimal             multiply by 0.01
decimal         numeric             multiply by 100.

I'm interested in a more pythonic alternative to the following dict lookup. Because I'll be calling this conversion a number of times I'd prefer *not* to use logical operators. (I think...)

convert = {('num', 'num') : 1.,
           ('dec', 'dec') : 1.,
           ('num', 'dec') : 0.01,
           ('dec', 'num') : 100.
          }

def converter(num, input_form='num', output_form='dec'):
    return num * convert[(input_form, output_form)]

num = 5.43
print(converter(num))

Is this question too broad? Comment and let me know, and I'll try to hone in on what I'm looking for, but frankly I'm just interested in seeing other implementations. Basically, I currently have a class-based implementation where I want to establish a numeral and decimal form of self at instantiation and then also use the function within methods as well.

You could also use properties:

class Convertible:
    def __init(self, value, form='numeric'):
        if form == 'numeric':
            self._numeric = value
        elif form == 'decimal':
            self._numeric = value * 100
        else:
            raise ValueError("form must be 'numeric' or 'decimal'")

    @property
    def numeric(self):
        return self._numeric

    @numeric.setter
    def numeric(self, value):
        self._numeric = value

    @property
    def decimal(self):
        # for Python 2 compatibility, divide by a float
        # to avoid integer division if we have an integer 'numeric' value
        return self._numeric / 100.0

    @decimal.setter
    def decimal(self, value):
        self._numeric = value * 100

So, you can set either the numeric or decimal form of your number, and access either one transparently. Internally, we store only one of the forms.

You can use it like this:

val = Convertible()

val.numeric = 5.43
print(val.numeric)
# 5.43
print(val.decimal)
# 0.054299999999999994

val.decimal = 0.42
print(val.numeric)
# 42.0
print(val.decimal)
# 0.42

You can find more information on properties here, for example

I currently have a class-based implementation where I want to establish a numeral and decimal form of self at instantiation and then also use the function within methods as well.

If you're already using a class-based approach, then it seems most natural to wrap the conversion up into properties of the class rather than dealing with a separate conversion dictionary.

class DecimalPercent:
    def __init__(self, value, form='decimal'):
        self._value = value/100 if form == 'percent' else value

    @property
    def decimal(self):
        return self._value

    @decimal.setter
    def decimal(self, value):
        self._value = value

    @property
    def percent(self):
        return self._value * 100

    @percent.setter
    def percent(self, value):
        self._value = value / 100

An alternative to using properties in this case—just so you're aware—would be to define two float subclasses and use them as shown below:

class Num(float):
    pass

class Dec(float):
    pass

def converter(value):
    arg_type = Num if isinstance(value, Num) else Dec if isinstance(value, Dec) else None
    return value * (0.01 if arg_type is Num else 100 if arg_type is Dec else float('nan'))

print(converter(Num(5.43)))  # -> 0.0543
print(converter(Dec(0.12)))  # -> 12.0
print(converter(0.1618))     # -> nan
print(converter(42))         # -> nan

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM