I was wondering if there is a way for a class to define a method that behaves like a static method (can be called without an instance variable) and a regular method (can be called with an instance variable).
Im making an RSA module that would help me solve RSA problems, the initialization goes like this:
class RSA:
def __init__(self, n: int, e: int, c: int, p=None, q=None, phi=None):
self.n = n
self.e = e
self.c = c
self.p = p
self.q = q
assert p == None or gmpy2.is_prime(p), 'p must be prime'
assert q == None or gmpy2.is_prime(q), 'q must be prime'
self.phi = phi
and in that class, there is a method that would factorize n into p and q which goes like this (the algorithm used is irrelevant so I wont bother explaining):
def fermat_factorization(self, n=None):
if n == None:
n = self.n
t_ = gmpy2.isqrt(n)+1
counter = 0
t = t_ + counter
temp = gmpy2.isqrt((t * t) - n)
while((temp * temp) != ((t * t) - n)):
counter += 1
t = t_ + counter
temp = gmpy2.isqrt((t * t) - n)
s = temp
p = t + s
q = t - s
return p, q
that implementation does not work. What I wanted to do is for that method to be dynamic, i.e. can be called externally by simply
p, q = RSA.fermat_factorization(n) # n is some large number
yet can also be called on an instance like:
s1 = RSA(n, 65537, c) # c and n is some large number
p, q = s1.fermat_factorization() # without specifying n because it is already an instance attribute
In python, you use modules for that kind of stuff, not classes:
in rsa.py
def fermat_factorization(n):
"""Ordinary function"""
class RSA:
def fermat_factorization(self):
"""Method"""
return fermat_factorization(self.n)
somewhere else:
import rsa
x = rsa.fermat_factorization(100)
obj = rsa.RSA(...)
y = obj.fermat_factorization()
Having a single function that behaves some way or another depending on how it's called is a recipe for disaster. Don't do that.
Related
Recently I was learning the sequence alignment algorithm. After I got the alignment matrix, I could find an optimal path, but I was in trouble when I was looking for multiple optimal paths (backtracking)!
My idea is to store the results of multiple paths with multiple instances, and finally loop through all instances of the base class to get the answer.
I know the following conditions:
What conditions to exit recursion
When do I need to create a new instance and when I don't create it?
But the problem is in the second condition. I don't know how many optimal results there are, and I don't know how many new instances will be created.
So I want to be able to dynamically generate an instance name with a variable.
I don't know how to do this:
# those equivalent to new_instance_name = ResultSeq()
a="new_instance_name"
create_new_instance(a,ResultSeq)
My result base class is ResultSeq:
class KeepRefs(object):
"""
reference:https://stackoverflow.com/questions/328851/printing-all-instances-of-a-class#comment167339_328851
"""
__refs__ = defaultdict(list)
def __init__(self):
self.__refs__[self.__class__].append(weakref.ref(self))
#classmethod
def get_instances(cls):
for inst_ref in cls.__refs__[cls]:
inst = inst_ref()
if inst is not None:
yield inst
class ResultSeq(KeepRefs):
"""
save two
"""
def __init__(self, seq1="", seq2=""):
super(ResultSeq, self).__init__()
self.seq1 = seq1
self.seq2 = seq2
Below is my recursive code:
def multi_backtracking(self, array, i, j, result_seq):
"""
:param array: V, E, F
:param i: row
:param j: col
:param result_seq: new instance of the class ResultSeq
:return: Multiple alignment results
"""
def create_new_obj(name, obj):
"""
I don't know how to do this.
"""
pass
if i == 0 and j == 0:
pass
else:
if array is self.array_V:
if sum(pass_judgement) == 1:
"""
An optimal path without creating a new instance.
"""
self.multi_backtracking(self.array_V, i, j, result_seq)
else:
"""
Multiple paths, need to create a new instance
"""
new_instance_name = "xxx"
create_new_obj(new_instance_name, ResultSeq)
...
if pass_judgement[0]:
result_seq.seq1 = self.origin_seq.seq1[i - 1] + result_seq.seq1
result_seq.seq2 = self.origin_seq.seq2[j - 1] + result_seq.seq2
self.multi_backtracking(self.array_V, i - 1, j - 1, new_instance_name)
if pass_judgement[1]:
self.multi_backtracking(self.array_E, i, j, new_instance_name)
if pass_judgement[2]:
self.multi_backtracking(self.array_F, i, j, new_instance_name)
This is just one of my solutions. If there are better suggestions, I will be happy to accept them, thank you!
You do not need names to store variables - you can use a simple list to store your instances:
class A:
def __init__(self,value):
self.value = value
def __repr__(self):
return f" _{self.value}_ "
def rec(i):
"""Recursive function, returns a list of instances of class A with decreasing
value i"""
if i < 0:
return []
return [A(i)] + rec(i-1)
k = rec(5)
print(k)
Output:
[ _5_ , _4_ , _3_ , _2_ , _1_ , _0_ ]
You can acccess your instances inside your list by indexing:
print(k[2]) # _3_
print(k[2].value + k[3].value) # 5
If you really need names, you can use a dictionary to store them - that is about the same as your existing baseclass KeepRefs does (*):
data = { "Instance1" : A(42), "Instance2" : A(3.141)}
print(data)
print( data["Instance1"].value + data["Instance2"].value )
Output:
{'Instance1': _42_ , 'Instance2': _3.141_ }
45.141
Most of the time when you need user generated "names" for variables you should very strongly reconsider your options.
(*) Your baseclass does not keep non-referenced instances around, a real dict will prevent garbage collecting:
k1 = ResultSeq("A","B")
k2 = ResultSeq("C","D")
k3 = ResultSeq("E","F")
for g in ResultSeq.get_instances():
print(g.seq1, g.seq2)
k2 = None # no instance of k2 anywhere
k3 = None # no instance of k3 anywhere
for g in ResultSeq.get_instances():
print(g.seq1, g.seq2)
A B
C D
E F
A B # 2.print loop after removing instances k2,k3
Documentation:
https://docs.python.org/3/library/weakref.html
I'm currently writing a code to perform Gaussian elimination in MATLAB and then write out the code needed to generate a LaTex file showing all the steps. A lot of the times when I do Gaussian elimination the answers start turning into Fractions. So I thought as a nice learning exercise for classes in Matlab that I would write a Fraction class. But I have no clue how to overload operators and frankly Mathwork's documentation wasn't helpful.
classdef Fraction
properties
numer
denom
end
methods
function a = Fraction(numer,denom)
a.denom = denom;
a.numer = numer;
end
function r = mtimes(a,b)
r = Fraction(a.numer*b.numer,a.denom*b.demon);
end
function r = plus(a,b)
c = a.numer*b.denom+a.denom*b.numer;
d = a.denom*b.denom;
r = Fraction(c,d);
function r = minus(a,b)
c = a.numer*b.denom-a.denom*b.numer;
d = a.denom*b.denom;
r = Fraction(c,d);
end
function r = mrdivide(a,b)
r = Fraction(a.numer*b.denom,a.denom*b.numer);
end
function b = reduceFrac(a)
x = a.numer;
y = b.denom;
while y ~= 0
x = y;
y = mod(x,y);
end
b =Fraction(a.numer/x, a.denom/x)
end
end
end
The plus operator works but the other three do not. Does any one have any ideas? Also how do I call my method reduceFrac?
Fraction.reduceFrac(Fraction(2.4))
I thought that the code above would work, but it didn't. Below is the python version of what I am trying to acheive.
Fraction.py
class Fraction(object):
"""Fraction class
Attributes:
numer: the numerator of the fraction.
denom: the denominator of the fraction.
"""
def __init__(self, numer, denom):
"""Initializes the Fraction class
Sets the inital numer and denom for the
fraction class.
Args:
numer: Top number of the Fraction
denom: Bottom number of the Fraction
Returns:
None
Raises:
None
"""
self.numer = numer
self.denom = denom
def __str__(self):
"""function call along with the print command
Args:
None
Returns:
String: numer / denom.
Raises:
None
"""
return str(self.numer) + '/' + str(self.denom)
def get_numer(self):
return self.numer
def set_numer(self, numer):
self.numer = numer
def get_denom(self):
return self.denom
def set_denom(self, denom):
self.denom = denom
def __add__(self, other):
numer = self.numer*other.denom+other.numer*self.denom
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def __div__(self, other):
numer = self.numer*other.denom
denom = self.denom*other.numer
return Fraction.reduceFrac(Fraction(numer,denom))
def __sub__(self, other):
numer = self.numer*other.denom-other.numer*self.denom
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def __mul__(self, other):
numer = self.numer*other.numer
denom = self.denom*other.denom
return Fraction.reduceFrac(Fraction(numer,denom))
def reduceFrac(self):
x = self.numer
y = self.denom
while y != 0:
(x, y) = (y, x % y)
return Fraction(self.numer/x, self.denom/x)
if __name__ == "__main__":
v = Fraction(4,3)
g = Fraction(7,8)
r = Fraction(4,8)
a = v + g
print a
s = v - g
print s
d = v / g
print d
m = v * g
print m
f = Fraction.reduceFrac(r)
print f
Your plus function misses an end
I've been told to write a simple program that generates coupon codes, which should offer more than two algorithms (any two) and that the algorithm and the number of codes generated should be read from a config file. Also I've been told that the solution would involve using a known design pattern and that I should look for what pattern is.
I've come up with two solutions for this, but I don't think I've found a proper OOP design pattern that fits for the problem, since objects are data with methods that operate over that data, and in this problem there is little data to operate over, it's more a function (functional?) problem to my naive eyes. Here are the two, one is basically executing the proper static method for the algorithm in the config file and the other returns a reference to a function. Both generate the numbers and print them to the screen.
First method:
class CouponGenerator:
SEQUENTIAL_NUMBERS = "sequentialNumbers"
FIBONACCI_NUMBERS = "fibonacciNumbers"
ALPHANUMERIC_SEQUENCE = "alphanumericSequence"
quantity = 0
algorithm = ""
def __init__(self, quantity, algorithm):
self.quantity = quantity
self.algorithm = algorithm
def generateCouponList(self):
numbers = list()
if self.algorithm == self.SEQUENTIAL_NUMBERS:
numbers = CouponGenerator.generateSequentialNumbers(self.quantity)
elif self.algorithm == self.FIBONACCI_NUMBERS:
numbers = CouponGenerator.generateFibonacciSequence(self.quantity)
for number in numbers:
print number
#staticmethod
def getCouponGenerator(configFile):
cfile = open(configFile)
config = cfile.read()
jsonconfig = json.loads(config)
cg = CouponGenerator(jsonconfig['quantity'], jsonconfig['algorithm'])
return cg
#staticmethod
def generateSequentialNumbers(quantity):
numbers = list()
for n in range(1, quantity+1):
zeroes = 6-len(str(n))
numbers.append(zeroes*"0"+str(n))
return numbers
#staticmethod
def generateFibonacciSequence(quantity):
def fib(n):
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return a
numbers = list()
for n in range(1, quantity+1):
number = fib(n)
zeros = 6-len(str(number))
numbers.append(zeros*"0"+str(number))
return numbers
if __name__ == "__main__":
generator = CouponGenerator.getCouponGenerator("config")
generator.generateCouponList()
Second solution:
class CouponGenerator:
#staticmethod
def getCouponGenerator(algorithm):
def generateSequentialNumbers(quantity):
numbers = list()
for n in range(1, quantity+1):
zeroes = 6-len(str(n))
numbers.append(zeroes*"0"+str(n))
return numbers
def generateFibonacciSequence(quantity):
def fib(n):
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return a
numbers = list()
for n in range(1, quantity+1):
number = fib(n)
zeros = 6-len(str(number))
numbers.append(zeros*"0"+str(number))
return numbers
generators = {"sequentialNumbers": generateSequentialNumbers,
"fibonacciNumbers": generateFibonacciSequence}
return generators[algorithm]
class CouponGeneratorApp:
configFile = "config"
def __init__(self):
cfile = open(self.configFile)
config = cfile.read()
self.jsonconfig = json.loads(config)
self.generateCouponCodes()
def generateCouponCodes(self):
generator = CouponGenerator.getCouponGenerator(self.jsonconfig["algorithm"])
numbers = generator(self.jsonconfig["quantity"])
for n in numbers:
print n
if __name__ == "__main__":
app = CouponGeneratorApp()
If you want to make it a little more object oriented I suggest you use some kind of strategy pattern, that means, use a class per generation algorithm (which should have a common interface) and specify that CouponGenrator use an object which implements this interface to do whatever it has to do. This is theory and making interface and everything in your case might be a little to much.
http://en.wikipedia.org/wiki/Strategy_pattern
you could try something like :
class SequentialGenerator(Object):
def implementation():
...
class FibonacciGenerator(Object):
def implementation():
...
class CouponGenerator(Object):
def set_generator(generator):
# set self.generator to either an instance
# of FibonacciGenerator or SequentialGenerator
def generate_coupon_code():
# at some point calls self.generator.implementation()
I've got a class called Point with many functions. I put an extract code:
#/usr/bin/env python3
# -*- coding: utf-8 -*-
from math import sqrt, pow, hypot, atan2, cos, sin
class Point(object):
__slots__ = ['x', 'y', 'z']
def __init__(self, x=0, y=0, z=None):
self.x = x
self.y = y
self.z = z
def __del__(self):
#del P destroy (delete) a point
class_name = self.__class__.__name__
def dist(self, P):
if self.z is not None:
d = sqrt(pow(self.x - P.x, 2) + pow(self.y - P.y, 2) +
pow(self.z - P.z, 2))
return d
else:
d = sqrt(pow(self.x - P.x, 2) + pow(self.y - P.y, 2))
return d
def pto_medio(self, P):
Q = Point(self.x, self.y)
if self.z is not None:
Q = Point(self.x, self.y, self.z)
else:
Q = Point(self.x, self.y)
R = (1. / 2.) * (P + Q)
return R
def entrada(self):
point = raw_input('Introduce un punto:\n')
point = point.replace('(', '')
point = point.replace(')', '')
l1 = point.rsplit(',')
self.x = float(l1[0])
self.y = float(l1[1])
if len(l1) == 3:
self.z = float(l1[2])
l1 = []
def __repr__(self):
if self.z is not None:
return('({}, {}, {})'.format(self.x, self.y, self.z))
else:
return('({}, {})'.format(self.x, self.y))
When I call the functions I put this code:
def main():
p = Point()
q = Point()
Point.entrada(p)
Point.entrada(q)
s = p + q
r = p - q
m = 5 * p
print(('Distancia = {}'.format(p.dist(q))))
print(('Punto Medio = {}'.format(p.pto_medio(q))))
if __name__ == '__main__':
main()
I put p.dist(q) and p.pto_medio(q) but I want to write dist(p, q) and pto_medio(p, q), respectivily. I've seen several solutions about that but all solutions give me error.
Thanks!
I don't know why you want to do this… but if you want to, it's easy.
In Python, an unbound method (that is, a method accessed as a member of the class object) can be called just like a function, by passing the self argument explicitly. So:
dist = Point.dist
pto_medio = Point.pto_medio
dist(p, q)
pto_medio(p, q)
In other words, the unbound method is the function you def'd in the class definition, with no magic whatsoever.*
If you want to know how this all works under the covers, see the Descriptor HOWTO and how methods work.
And there are plenty of cases where this is useful, beyond just adapting two pieces of code that were written incompatibly. For example, map and filter don't take a function, they take any callable. Sometimes it makes sense to pass them an unbound method:
with open(path) as f:
strippedlines = map(str.strip, f)
If you couldn't pass unbound methods around like functions, you'd have to write that as:**
with open(path) as f:
strippedlines = map(lambda line: line.strip(), f)
* In Python 2.x, this isn't true; an unbound method is instead a bound method with None for the bound instance, and there's special magic to make it work. But in 3.0+, unbound methods are just plain functions.
** Well, actually you could just use a comprehension: (line.strip() for line in f). But if you wanted to use map, you'd have to build a wrapper.
I'm getting a getting a TypeError for unbound method (at the bottom). I'm teaching myself Python so this may be some simple mistake. The issue is with outFormat(), which didn't give me problems when I test it by itself but is not working within the class. Here's the class:
class gf2poly:
#binary arithemtic on polynomials
def __init__(self,expr):
self.expr = expr
def id(self):
return [self.expr[i]%2 for i in range(len(self.expr))]
def listToInt(self):
result = gf2poly.id(self)
return int(''.join(map(str,result)))
def prepBinary(a,b):
a = gf2poly.listToInt(a); b = gf2poly.listToInt(b)
bina = int(str(a),2); binb = int(str(b),2)
a = min(bina,binb); b = max(bina,binb);
return a,b
def outFormat(raw):
raw = str(raw); g = []
[g.append(i) for i,c in enumerate(raw) if c == '1']
processed = "x**"+' + x**'.join(map(str, g[::-1]))
#print "processed ",processed
return processed
def divide(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
bitsa = "{0:b}".format(a); bitsb = "{0:b}".format(b)
difflen = len(str(bitsb)) - len(str(bitsa))
c = a<<difflen; q=0
while difflen >= 0 and b != 0:
q+=1<<difflen; b = b^c
lendif = abs(len(str(bin(b))) - len(str(bin(c))))
c = c>>lendif; difflen -= lendif
r = "{0:b}".format(b); q = "{0:b}".format(q)
#print "r,q ",type(r),type(q)
return r,q #returns r remainder and q quotient in gf2 division
def remainder(a,b): #separate function for clarity when calling
r = gf2poly.divide(a,b)[0]; r = int(str(r),2)
return "{0:b}".format(r)
def quotient(a,b): #separate function for clarity when calling
q = gf2poly.divide(a,b)[1]; q = int(str(q),2)
return "{0:b}".format(q)
This is how I'm calling it:
testp = gf2poly.quotient(f4,f2)
testr = gf2poly.remainder(f4,f2)
print "quotient: ",testp
print "remainder: ",testr
print "***********************************"
print "types ",type(testp),type(testr),testp,testr
testp = str(testp)
print "outFormat testp: ",gf2poly.outFormat(testp)
#print "outFormat testr: ",gf2poly.outFormat(testr)
This is the error:
TypeError: unbound method outFormat() must be called with gf2poly instance as first argument (got str instance instead)
Where you have this:
def outFormat(raw):
You probably want either this:
def outFormat(self, raw):
Or this:
#staticmethod
def outFormat(raw):
The former if you eventually need access to self in outFormat(), or the latter if you do not (as currently is the case in the posted code).