1 | from numbers import Real |
||
2 | from math import isnan |
||
3 | |||
4 | #: A constant representing unknown value (NaN). Use this for storing unknowns, |
||
5 | #: but not for checking for unknowns. |
||
6 | Unknown = float("nan") |
||
7 | |||
8 | |||
9 | class Value(float): |
||
10 | """ |
||
11 | The class representing a value. The class is not used to store values but |
||
12 | only to return them in contexts in which we want the value to be accompanied |
||
13 | with the descriptor, for instance to print the symbolic value of discrete |
||
14 | variables. |
||
15 | |||
16 | The class is derived from `float`, with an additional attribute `variable` |
||
17 | which holds the descriptor of type :obj:`Orange.data.Variable`. If the |
||
18 | value continuous or discrete, it is stored as a float. Other types of |
||
19 | values, like strings, are stored in the attribute `value`. |
||
20 | |||
21 | The class overloads the methods for printing out the value: |
||
22 | `variable.repr_val` and `variable.str_val` are used to get a suitable |
||
23 | representation of the value. |
||
24 | |||
25 | Equivalence operator is overloaded as follows: |
||
26 | |||
27 | - unknown values are equal; if one value is unknown and the other is not, |
||
28 | they are different; |
||
29 | |||
30 | - if the value is compared with the string, the value is converted to a |
||
31 | string using `variable.str_val` and the two strings are compared |
||
32 | |||
33 | - if the value is stored in attribute `value`, it is compared with the |
||
34 | given other value |
||
35 | |||
36 | - otherwise, the inherited comparison operator for `float` is called. |
||
37 | |||
38 | Finally, value defines a hash, so values can be put in sets and appear as |
||
39 | keys in dictionaries. |
||
40 | |||
41 | .. attribute:: variable (:obj:`Orange.data.Variable`) |
||
42 | |||
43 | Descriptor; used for printing out and for comparing with strings |
||
44 | |||
45 | .. attribute:: value |
||
46 | |||
47 | Value; the value can be of arbitrary type and is used only for variables |
||
48 | that are neither discrete nor continuous. If `value` is `None`, the |
||
49 | derived `float` value is used. |
||
50 | """ |
||
51 | __slots__ = "variable", "_value" |
||
52 | |||
53 | def __new__(cls, variable, value=Unknown): |
||
54 | """ |
||
55 | Construct a new instance of Value with the given descriptor and value. |
||
56 | If the argument `value` can be converted to float, it is stored as |
||
57 | `float` and the attribute `value` is set to `None`. Otherwise, the |
||
58 | inherited float is set to `Unknown` and the value is held by the |
||
59 | attribute `value`. |
||
60 | |||
61 | :param variable: descriptor |
||
62 | :type variable: Orange.data.Variable |
||
63 | :param value: value |
||
64 | """ |
||
65 | if not isinstance(value, str): |
||
66 | try: |
||
67 | self = super().__new__(cls, value) |
||
68 | except: |
||
0 ignored issues
–
show
|
|||
69 | self = super().__new__(cls, -1) |
||
70 | else: |
||
71 | self = super().__new__(cls, -1) |
||
72 | self._value = value |
||
0 ignored issues
–
show
It seems like
_value was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
![]() |
|||
73 | self.variable = variable |
||
74 | return self |
||
75 | |||
76 | def __init__(self, _, __=Unknown): |
||
0 ignored issues
–
show
The
__init__ method of the super-class float is not called.
It is generally advisable to initialize the super-class by calling its class SomeParent:
def __init__(self):
self.x = 1
class SomeChild(SomeParent):
def __init__(self):
# Initialize the super class
SomeParent.__init__(self)
![]() |
|||
77 | pass |
||
78 | |||
79 | def __repr__(self): |
||
80 | return "Value('%s', %s)" % (self.variable.name, |
||
81 | self.variable.repr_val(self)) |
||
82 | |||
83 | def __str__(self): |
||
84 | return self.variable.str_val(self) |
||
85 | |||
86 | def __eq__(self, other): |
||
87 | if isinstance(self, Real) and isnan(self): |
||
88 | return (isinstance(other, Real) and isnan(other) |
||
89 | or other in self.variable.unknown_str) |
||
90 | if isinstance(other, str): |
||
91 | return self.variable.str_val(self) == other |
||
92 | if isinstance(other, Value): |
||
93 | return self.value == other.value |
||
94 | return super().__eq__(other) |
||
95 | |||
96 | def __contains__(self, other): |
||
97 | if (self.value is not None |
||
98 | and isinstance(self.value, str) |
||
99 | and isinstance(other, str)): |
||
100 | return other in self.value |
||
101 | raise TypeError("invalid operation on Value()") |
||
102 | |||
103 | def __hash__(self): |
||
104 | if self.value is None: |
||
105 | return super().__hash__() |
||
106 | else: |
||
107 | return super().__hash__() ^ hash(self.value) |
||
108 | |||
109 | @property |
||
110 | def value(self): |
||
111 | if self.variable.is_discrete: |
||
112 | return Unknown if isnan(self) else self.variable.values[int(self)] |
||
113 | if self.variable.is_string: |
||
114 | return self._value |
||
115 | return float(self) |
||
116 | |||
117 | def __getnewargs__(self): |
||
118 | return self.variable, float(self) |
||
119 | |||
120 | def __getstate__(self): |
||
121 | return dict(value=getattr(self, '_value', None)) |
||
122 | |||
123 | def __setstate__(self, state): |
||
124 | self._value = state.get('value', None) |
||
125 |
Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.