In the code below, I defined '<' in the magic method __lt__(), which will return True if the first argument is less than the second one, return False otherwise.
from functools import total_ordering
#total_ordering
class Currency:
"""
One object of class Currency stores one amount of money, dollars and cents.
"""
def __add__(self, other):
"""
returns the result of adding self to other
"""
total = Currency(self.dollars, self.cents)
total.dollars = total.dollars + other.dollars
print (other.dollars)
total.cents = total.cents + other.cents
print (other.cents)
if total.cents > 100:
total.cents = total.cents - 100
total.dollars = total.dollars +1
return total
def __init__(self, dollars=0, cents=0):
self.dollars = dollars
self.cents = cents
def __str__(self):
return "$"+str(self.dollars)+"."+str(self.cents)
def __eq__(self, other):
return self.dollars==other.dollars and self.cents==other.cents
def __lt__(self, other):
if self.dollars<other.dollars:
return True
elif self.dollars > other.dollars:
return False
else: # dollars are equal
return self.cents < other.cents
And then I called __lt__() in the test program with '<'. In this case, the candyPrice(first argument) is less than bookPrice(second argument), so it returned True as expected. And then, I compared these two values with '>' which was not predefined in class Currency, but it also returned False as expected. So I'm wondering if it's because __lt__() was defined already, then the opposite expression, the '>' expression, was also implicitly defined?
if __name__ == "__main__":
candyPrice = Currency (1, 17) # $1.17
bookPrice = Currency (12, 99) # $12.99
print (candyPrice < bookPrice)
print (candyPrice > bookPrice)
You used the #total_ordering class decorator. This decorator explicitly adds the other methods for you.
From the #functools.total_ordering documentation:
Given a class defining one or more rich comparison ordering methods, this class decorator supplies the rest. This simplifies the effort involved in specifying all of the possible rich comparison operations:
The class must define one of __lt__(), __le__(), __gt__(), or __ge__(). In addition, the class should supply an __eq__() method.
So even though you did not define a __gt__ method, the class decorator has defined one for you using your __lt__ method, together with __eq__.
For example, when defining a __lt__ method, the __gt__() implementation is set to:
def _gt_from_lt(self, other, NotImplemented=NotImplemented):
'Return a > b. Computed by #total_ordering from (not a < b) and (a != b).'
op_result = self.__lt__(other)
if op_result is NotImplemented:
return op_result
return not op_result and self != other
So if self < other is false, self != other is used. You did not define a __ne__ method, but you did provide a __eq__ and the default for __ne__ is then to return not self.__eq__(other); see the object.__ne__() documentation:
By default, __ne__() delegates to __eq__() and inverts the result unless it is NotImplemented.
For your test Currency instances __eq__ is not needed, candyPrice.__gt__(bookPrice) calls candyPrice.__lt__(bookPrice), which returns true and thus False is returned without checking for self != other.
Related
I was reading about the 2-SAT problem on Wikipedia and I was wondering what the O(n) algorithm looks like in Python.
So far I've only found implementations that either are in other programming languages or that just determine whether an expression has solutions or not, without given the solution itself.
How could the O(n) algorithm for finding the values of variables be written in Python?
Here is an OOP implementation in Python:
import re
class TwoSat:
class Variable:
def __init__(self, name, negated=None):
self.name = name
self.negated = negated or TwoSat.Variable("~" + name, self)
self.implies = set()
self.impliedby = set()
self.component = -1
def disjunction(self, b):
self.negated.implication(b)
b.negated.implication(self)
def implication(self, b):
self.implies.add(b)
b.impliedby.add(self)
def postorder(self, visited):
if self not in visited:
visited.add(self)
for neighbor in self.implies:
yield from neighbor.postorder(visited)
yield self
def setcomponent(self, component):
if self.component == -1:
self.component = component
for neighbor in self.impliedby:
neighbor.setcomponent(component)
def value(self):
diff = self.component - self.negated.component
return diff > 0 if diff else None
### end of class Variable
def __init__(self, s):
self.variables = {}
for a_neg, a_name, b_neg, b_name in re.findall(r"(~)?(\w+).*?(~)?(\w+)", s):
self.getvariable(a_neg, a_name).disjunction(self.getvariable(b_neg, b_name))
def getvariable(self, neg, name):
if name not in self.variables:
self.variables[name] = TwoSat.Variable(name)
self.variables["~" + name] = self.variables[name].negated
a = self.variables[name]
return a.negated if neg else a
def postorder(self):
visited = set()
for startvariable in self.variables.values():
yield from startvariable.postorder(visited)
def setcomponents(self):
for i, variable in enumerate(reversed(list(self.postorder()))):
variable.setcomponent(i)
def issolved(self):
return all(variable.value() is not None for variable in self.variables.values())
def solve(self):
self.setcomponents()
return self.issolved()
def truevariables(self):
if self.issolved():
return [variable.name for variable in self.variables.values() if variable.value()]
def __repr__(self):
return " ∧ ".join(
f"({a.name} → {b.name})"
for a in self.variables.values()
for b in a.implies
)
Here is an example of how this class can be used:
problem = TwoSat("(~a+~b)*(b+~c)*(c+g)*(d+a)*(~f+i)*(~i+~j)*(~h+d)*(~d+~b)*(~f+c)*(h+~i)*(i+~g)")
print(problem)
problem.solve()
print("solution: ", problem.truevariables())
The TwoSat constructor takes one argument, a string, which should provide the conjugation of disjunction pairs. The syntax rules for this string are:
literals must use alphanumeric characters (underscores allowed), representing a variable, optionally prefixed with a ~ to denote negation.
All other characters are just taken as separators and are not validated.
All literals are taken in pairs and each consecutive pair is assumed to form a disjunction clause.
If the number of literals is odd, then although that expression is not a valid 2SAT expression, the last literal is simply ignored.
So the above example could also have taken this string representing the same problem:
problem = TwoSat("~a ~b b ~c c g d a ~f i ~i ~j ~h d ~d ~b ~f c h ~i i ~g")
Alternatively, you can use the getvariable and disjunction methods to build the expression. Look at the __init__ method how the constructor uses those methods when parsing the string. For example:
problem = TwoSat()
for variable in "abcdefghij":
problem.getvariable(False, variable)
# Define the disjunction ~a + ~b:
problem.variables["a"].negated.disjunction(problem.variables["b"].negated)
# ...etc
The algorithm is the one explained in the 2-satisiability article on Wikipedia, identifying strongly connected components using Kosaraju's algorithm
For example: What if I wanted to create the class My_Number and create a class inside of My_Number called Odd_Or_Even that had two methods: The first method, odd, would return True if the number is odd, and False if it's not. The opposite goes for the second method, even. Should I create an __init__ method for Odd_Or_Even that takes an instance of My_Number as an argument so that it would have access to the number? Let's also say that My_Number has a method called add that adds a random value from 1 to 100 to the number so that My_Number isn't useless.
Also, I realize that it would be more efficient to just create a method called either odd or even that return True if the number is either odd or even respectively, but I could not think of a better example than this.
from random import randint
class My_Number:
def __init__(self,number):
self.number=number
class Odd_Or_Even:
def __init__(self,My_Number_instance):
self.My_Number_instance=My_Number_instance
def odd(self):
if self.My_Number_instance.number%2!=0:
return True
else:
return False
def even(self):
if self.My_Number_instance.number%2==0:
return True
else:
return False
def add(self):
self.number+=randint(1,100)
is it possible to modify the PyQt spinbox to work with integers bigger than 32bit (-2147483648 - 2147483647)? I know its possible to write a new spinbox in C++ with 64 bit int data type, but this would be to complicate.
You can get a spin box with values greater than 32bit by using QDoubleSpinBox.
As the name suggests, this will give you double (i.e. floating-point) values with a maximum of 2**53 (9,007,199,254,740,992). If you want integer values, just set the precision to zero by using setDecimals(0). (NB: for some reason, Qt Designer won't allow you to set a maximum value greater than 99,999,999 for either of the built-in spin-boxes, so you'll have to do it "manually").
If you want values greater than 2**53, subclass QAbstractSpinBox, reimplement the relevant methods (stepBy, stepEnabled, validate and possibly fixup), and then provide whatever other methods (e.g. value/setValue) that you deem necessary.
Many thanks for the hints. I tried the QDoubleSpinBox but didn't tried to set the values manually. Cause it doesn't fit my purposes I've written my own spinbox. Below the code. Maybe its helpful for someone else. Documentation about subclassing QAbstractSpinBox is a bit rare.
The default maximum is consistent with numpy.uint64's maximum. In theory there should be no limit, cause an QLineEdit is used for representation. If you need numbers longer than 20 signs simply adapt the validators regular expression.
class BigIntSpinbox(QtGui.QAbstractSpinBox):
def __init__(self, parent=None):
super(BigIntSpinbox, self).__init__(parent)
self._singleStep = 1
self._minimum = -18446744073709551616
self._maximum = 18446744073709551615
self.lineEdit = QtGui.QLineEdit(self)
rx = QtCore.QRegExp("[1-9]\\d{0,20}")
validator = QtGui.QRegExpValidator(rx, self)
self.lineEdit.setValidator(validator)
self.setLineEdit(self.lineEdit)
def value(self):
try:
return int(self.lineEdit.text())
except:
raise
return 0
def setValue(self, value):
if self._valueInRange(value):
self.lineEdit.setText(str(value))
def stepBy(self, steps):
self.setValue(self.value() + steps*self.singleStep())
def stepEnabled(self):
return self.StepUpEnabled | self.StepDownEnabled
def setSingleStep(self, singleStep):
assert isinstance(singleStep, int)
# don't use negative values
self._singleStep = abs(singleStep)
def singleStep(self):
return self._singleStep
def minimum(self):
return self._minimum
def setMinimum(self, minimum):
assert isinstance(minimum, int) or isinstance(minimum, long)
self._minimum = minimum
def maximum(self):
return self._maximum
def setMaximum(self, maximum):
assert isinstance(maximum, int) or isinstance(maximum, long)
self._maximum = maximum
def _valueInRange(self, value):
if value >= self.minimum() and value <= self.maximum():
return True
else:
return False
I want to store pairs (prio,val) of heterogeneous types in a python PriorityQueue. Here val can be either a string or a custom class object.
When prio are equals, the PriorityQueue (actually heapq) implementation comes to compare the second member, thus comparing a string and a custom objects.
Depending on the order the elements were stored, it comes to compare either:
custom_object < string
string < custom_object
Case 1. translates to custom_object.__lt__(string) and this is fine, as i can overload the def __lt__:method in my custom class.
Case 2. : i am stuck because i do not know how to redefine __lt__ for strings.
Below is a MWE that inserts 3 elements with equal priorities (the value 1).
Running it results in the error message:
TypeError: '<' not supported between instances of 'str' and 'C'
import queue
class C:
def __init__(self,value):
__value__ = value
def __lt__(selfself,other):
return 0
q = queue.PriorityQueue()
tuple1=(1,"t1")
tuple2=(1,C("t2"))
tuple3=(1,"t3")
q.put(tuple1)
q.put(tuple2)
q.put(tuple3)
print( q.get())
If a does not supply an implementation for a < b, then Python will look for an implementation of b > a next.
class C:
def __lt__(self, other):
return 0
def __gt__(self, other):
return 1
c = C()
print(c < 'a') # 0
print('a' < c) # 1
I'm doing a Python 3 based data conversion and certain character based fields I operate on have specific character allowances and length constraints applied to them.
I'd want to have some sort of swappable/configurable constraint function I roll myself that I could call.
Can you extend str?
Is it best to define a class for this and make variables implementations of that class.
Or are there simpler ways to do this with Python 3?
I'm wondering if anyone can give me pointers as to what to Google for inspiration?
(My initial thoughts are to look at SQLAlchemy's internal code for inspiration for things like Column).
EDIT: SQLAlchemy's code is too sophisticated for this scenario!
For example a type that only allows:
alphanumerics (upper+lowercase)
numerics
plus a selection of special characters.
This may vary by field, but some may use same function.
Hence desire to create custom re-usable types.
I'll do character stripping or substitution.
Then one may only allow 50 chars, whilst another may allow 500 etc.
I'll pass back a tuple with original value, converted value, a boolean to indicate truncation occurred
This is what I ended up with:
valobj.py
import utils
class UDT:
def __init__(self, converter, maxlen, value):
if utils.getClassName(converter) != 'function':
raise TypeError(f'converter {converter} is not a function')
if int(maxlen) <= 0:
raise TypeError(f'maxlen {maxlen} must be 1 or more')
if utils.getClassName(value) != 'str':
raise TypeError(f'value {value} is not a Python String')
self.converter = converter
self.maxlen = int(maxlen)
self.value = value
def convert(self):
intermed = self.converter(self.value)
truncated = len(intermed) > self.maxlen
result = intermed[:self.maxlen] if truncated else intermed
return (result, truncated, self.value)
class Job:
def __init__(self, name):
self._name_tuple = UDT(utils.fix_chars, 64, name).convert()
utils.py
import string
def getClassName(arg):
return(str(type(arg)).replace("<class '","").replace("'>",""))
def fix_chars(text) -> str:
result = ''
for c in text:
if ( (string.ascii_letters.find(c) != -1)
or (string.digits.find(c) != -1)
or ('._-#'.find(c) != -1)
):
result += c
else:
result += '_'
result = tidy_up_str(result)
return (result)
def tidy_up_str(text) -> str:
result = text
result = result.replace('_-_', '_')
while result.find('__') != -1:
result = result.replace('__', '_')
if result.endswith('_'):
result = result[:-1]
return result