I'm attempting to create a custom form field that works the same as float field for all intents and purposes, but that (by default) outputs the float value with no trailing zeros e.g. 33 rather than 33.0
I attempted to simply extend django.forms.FloatField like so:
class CustomFloatField(django.forms.FloatField):
def to_python(self, value):
"""
Returns the value without trailing zeros.
"""
value = super(django.forms.FloatField, self).to_python(value)
# code to strip trailing zeros
return stripped_value
But this ended up with me getting validation errors. When I looked closer at the FloatField class I noticed that in its own to_python() method it calls super(IntegerField, self).to_python(value) which checks to ensure the value can be cast to an int, and it was here that my code seemed to trip up. This has left me thoroughly confused. How does FloatField work at all if it has to try and cast it's value to an int? :)
Most likely I'm barking entirely up the wrong tree here but if someone could point me in the right direction I'd be grateful.
Your hunch is right - FloatField isn't really calling on the to_python method of IntegerField. To illustrate what's really going on,
class A(object):
def __init__(self):
print "A initialized"
def to_python(self, value):
print "A: to_python"
return value
class B(A):
def __init__(self):
print "B initialized"
def to_python(self, value):
value = super(B, self).to_python(value)
print "B: value = "
print int(value)
return int(value)
class C(B):
def to_python(self, value):
value = super(B, self).to_python(value)
print "C: value = "
print float(value)
return float(value)
c = C()
c.to_python(5.5)
gives the output,
B initialized
A: to_python
C: value =
5.5
To put it in context, the line in FloatField's to_python:
value = super(IntegerField, self).to_python(value)
is really calling up to Field's to_python, which is simply,
def to_python(self, value):
return value
before calling the rest of the code. This might help you further: Understanding Python super() with __init__() methods
Related
i create new Column and add customize render as below
class PriceColumn(django_tables2.Column):
def render(self, value):
if isinstance(value, int) or isinstance(value, float):
self.attrs['td']['title'] = f'{round(value, 2):,}'
return number_convertor_to_milion(value)
return '---
then i used it for field
weekly_returns = PriceColumn(verbose_name=_('Weekly Returns'))
def render_weekly_returns(self, value,**kwargs):
final_result = value*100
// i want to call super().render() like below
return super().render(final_result,**kwargs)
i want to call super as in code writed but gives error
AttributeError: 'super' object has no attribute 'render'
how can do this?
In your case super() is referring to the class it's in, which is the MyTable(tables.Table) class, not the intended PriceColumn(Column) class.
You can fix one of 2 ways, call to the Class method directly;
def render_weekly_returns(self, value,**kwargs):
final_result = value*100
return PriceColumn.render(final_result,**kwargs)
or I would probably recommend just adding the return method instructions into your render_weekly_returns() method as it's going to be easier to read in the future.
def render_weekly_returns(self, value,**kwargs):
final_result = value*100
if isinstance(final_result, int) or isinstance(final_result, float):
self.attrs['td']['title'] = f'{round(final_result, 2):,}'
return number_convertor_to_milion(final_result)
return '---'
I'm really at a loss here. I need to pass arguments to the wrapper; these arguments change with runtime. Any idea how this could be solved using wrappers for classes?
def wrapper(x=None):
def decorate(cls):
def fct(self):
print('wrapper argument is: %s' % x)
cls.fct = fct
return cls
return decorate
a = 'first'
#wrapper(x=a)
class Test():
pass
test = Test()
test.fct() # Prints: first
a = 'second'
test.fct() # Prints: first (instead of second)
I can't put code in a comment, so here's how you'd do it.
def wrapper(x=None):
def decorate(cls):
def fct(self):
print('wrapper argument is: %s' % x[0])
cls.fct = fct
return cls
return decorate
a = ['first']
#wrapper(x=a)
class Test():
pass
test = Test()
test.fct() # Prints: first
a[0] = 'second'
test.fct() # Prints: second
The key is that strings are immutable, whereas lists are mutable. When you pass in a string, it's basically copied. When you pass in a list, you're sort of passing a reference to the original list, which is itself mutable.
python class's instance is behaving inconsistently.
Code.1
class A():
def __init__(self, x):
self.x = x
def update(self, x):
self.x = x
a = A(3)
a.update(5)
print a.x # prints 5
Code.2
class A():
def __init__(self, x):
self.x = x
def update(self, x):
self = A(x)
a = A(3)
a.update(5)
print a.x # prints 3
Why is 'x' attribute getting updated in the first snippet and is not getting updated in 2nd one?
Assigning to self does not change the current object. It just assigns a new value to the (local) self parameter variable.
The only special treatment that the self gets is during invocation, in the sense that
a.update(x)
is equivalent to
A.update(a, x)
Assigning to self just overrides the value of the local parameter:
def update(self, x):
# overwrite the value of self with a different instance of A
# This has no effect outside of update().
self = A(x)
a = A(3)
a.update(5)
In this case a is still the same instance from A(3). You created a new instance of A inside update() and assigned it to the self parameter, but that modification does not carry over outside of update().
I have an enum like this
#enum.unique
class TransactionTypes(enum.IntEnum):
authorisation = 1
balance_adjustment = 2
chargeback = 3
auth_reversal = 4
Now i am assigning a variable with this enum like this
a = TransactionTypes
I want to check for the type of 'a' and do something if its an enum and something else, if its not an enum
I tried something like this
if type(a) == enum:
print "do enum related stuff"
else:
print "do something else"
The problem is it is not working fine.
Now i am assigning a variable with this enum like this
a = TransactionTypes
I hope you aren't, because what you just assigned to a is the entire enumeration, not one of its members (such as TransactionTypes.chargeback) If that is really what you wanted to do, then the correct test would be:
if issubclass(a, enum.Enum)
However, if you actually meant something like:
a = TransactionTypes.authorisation
then the test you need is:
# for any Enum member
if isinstance(a, Enum):
or
# for a TransactionTypes Enum
if isinstance(a, TransactionTypes):
reliable solution:
from enum import IntEnum
from collections import Iterable
def is_IntEnum(obj):
try:
return isinstance(obj, Iterable) and isinstance (next(iter(obj)), IntEnum)
except:
return False # Handle StopIteration, if obj has no elements
I thought I`ve got a ugly way. eg:
print(o.__class__.__class__)
Output:
<enum.EnumMeta>
as mentioned use isinstance method to check weather an instance is of enum.Enum type or not.
A small working code for demonstration of its usage:
import enum
class STATUS(enum.Enum):
FINISHED = enum.auto()
DELETED = enum.auto()
CANCELLED = enum.auto()
PENDING = enum.auto()
if __name__ == "__main__":
instance = STATUS.CANCELLED
if isinstance(instance, enum.Enum):
print('name : ', instance.name, ' value : ', instance.value)
else:
print(str(instance))
Output:
name : CANCELLED value : 3
There are already good answers here but in case of it might be useful for some people out there
I wanted to stretch the question a little further and created a simple example
to propose a humble solution to help caller function who does maybe little knowledge about Enum
solve problem of sending arguments to functions that take only Enum
as a parameter by proposing a converter just below the file that Enum was created.
from enum import Enum
from typing import Union
class Polygon(Enum):
triangle: 3
quadrilateral: 4
pentagon: 5
hexagon: 6
heptagon: 7
octagon: 8
nonagon: 9
decagon: 10
def display(polygon: Polygon):
print(f"{polygon.name} : {polygon.value} ")
def do_something_with_polygon(polygon: Polygon):
"""This one is not flexible cause it only accepts a Polygon Enum it does not convert"""
""" if parameter is really a Polygon Enum we are ready to do stuff or We get error """
display(polygon)
def do_something_with_polygon_more_flexible(maybe_polygon_maybe_not: Union[Polygon, int, str]):
""" it will be more convenient function by taking extra parameters and converting"""
if isinstance(maybe_polygon_maybe_not, Enum):
real_polygon = maybe_polygon_maybe_not
else:
real_polygon = get_enum_with_value(int(maybe_polygon_maybe_not), Polygon, Polygon.quadrilateral)
""" now we are ready to do stuff """
display(real_polygon)
def get_enum_with_value(key: int, enum_: any, default_value: Enum):
""" this function will convert int value to Enum that corresponds checking parameter key """
# create a dict with all values and name of Enum
dict_temp = {x.value: x for x in
enum_} # { 3 : Polygon.triangle , 4 :Polygon.quadrilateral , 5 : Polygon.pentagon , ... }
# if key exists for example 6 or '6' that comes to do_something_with_polygon_more_flexible
# returns Polygon.hexagon
enum_value = dict_temp.get(key, None)
# if key does not exist we get None
if not enum_value:
... # if key does not exist we return default value (Polygon.quadrilateral)
enum_value = default_value # Polygon.quadrilateral
return enum_value
May be I do not completely understand the concept of properties in python, but I am confused by the behaviour of my Python program.
I have a class like this:
class MyClass():
def __init__(self, value):
self._value = value
#property
def value(self):
return self._value
#value.setter
def value(self, value):
self._value = value
What I would expect is, that calling MyClass.value = ... changes the content of _value. But what actually happened is this:
my_class = MyClass(1)
assert my_class.value == 1 # true
assert my_class._value == 1 # true
my_class.value = 2
assert my_class.value == 2 # true
assert my_class._value == 2 # false! _value is still 1
Did I make a mistake while writing the properties or is this really the correct behaviour? I know that I should not call my_class._value for reading the value, but nevertheless I would expect that it should work, anyway. I am using Python 2.7.
The class should inherit object class (in other word, the class should be new-style class) to use value.setter. Otherwise setter method is not called.
class MyClass(object):
^^^^^^