Printing an object python class - python

I wrote the following program:
def split_and_add(invoer):
rij = invoer.split('=')
rows = []
for line in rij:
rows.append(process_row(line))
return rows
def process_row(line):
temp_coordinate_row = CoordinatRow()
rij = line.split()
for coordinate in rij:
coor = process_coordinate(coordinate)
temp_coordinate_row.add_coordinaterow(coor)
return temp_coordinate_row
def process_coordinate(coordinate):
cords = coordinate.split(',')
return Coordinate(int(cords[0]),int(cords[1]))
bestand = file_input()
rows = split_and_add(bestand)
for row in range(0,len(rows)-1):
rij = rows[row].weave(rows[row+1])
print rij
With this class:
class CoordinatRow(object):
def __init__(self):
self.coordinaterow = []
def add_coordinaterow(self, coordinate):
self.coordinaterow.append(coordinate)
def weave(self,other):
lijst = []
for i in range(len(self.coordinaterow)):
lijst.append(self.coordinaterow[i])
try:
lijst.append(other.coordinaterow[i])
except IndexError:
pass
self.coordinaterow = lijst
return self.coordinaterow
However there is an error in
for row in range(0,len(rows)-1):
rij = rows[row].weave(rows[row+1])
print rij
The outcome of the print statement is as follows:
[<Coordinates.Coordinate object at 0x021F5630>, <Coordinates.Coordinate object at 0x021F56D0>]
It seems as if the program doesn't acces the actual object and printing it. What am i doing wrong here ?

This isn't an error. This is exactly what it means for Python to "access the actual object and print it". This is what the default string representation for a class looks like.
If you want to customize the string representation of your class, you do that by defining a __repr__ method. The typical way to do it is to write a method that returns something that looks like a constructor call for your class.
Since you haven't shown us the definition of Coordinate, I'll make some assumptions here:
class Coordinate(object):
def __init__(self, x, y):
self.x, self.y = x, y
# your other existing methods
def __repr__(self):
return '{}({}, {})'.format(type(self).__name__, self.x, self.y)
If you don't define this yourself, you end up inheriting __repr__ from object, which looks something like:
return '<{} object at {:#010x}>'.format(type(self).__qualname__, id(self))
Sometimes you also want a more human-readable version of your objects. In that case, you also want to define a __str__ method:
def __str__(self):
return '<{}, {}>'.format(self.x, self.y)
Now:
>>> c = Coordinate(1, 2)
>>> c
Coordinate(1, 2)
>>> print(c)
<1, 2>
But notice that the __str__ of a list calls __repr__ on all of its members:
>>> cs = [c]
>>> print(cs)
[Coordinate(1, 2)]

Related

TypeError: cannot unpack non-iterable GetColorImage object

i have following situation:
cratecolor.py: (code stripped to its minimum...)
import ... ...
class GetColorImage:
def __init__(self, ia=None):
self.path = None
self.img = None
self.img0 = None
self.s = None
self.basetime = 0
self.count = 0
self.stride = 32
self.ia = ia
self.img_size = 640
self.auto = True
self.getImage()
def getImage(self):
self.ia.remote_device.node_map.ExposureTime.value = 350
self.ia.remote_device.node_map.Gain.value = 150
...
...
print(color, l) # prints: 1 59.64829339143065
return color, l
main.py: (code stripped to its minimum)
...
...
# code exectued on a qthread:
def getcolor(self, idin):
color, lightness = cratecolor.GetColorImage(ia=self.ia) #******
print(color, lightness)
In the line marked with ***** i get the error message color, lightness = cratecolor.GetColorImage(ia=self.ia) TypeError: cannot unpack non-iterable GetColorImage object but i dont get why.
any help appreciated.
You cannot return values from an __init__ function, so you instead must either:
Call the getImage() method when creating the class
Define an __iter__ method for the class to automatically allow you to assign it to multiple variables.
The second one is probably the better solution. Here is the method you would add to the class for it to work:
def __iter__(self):
return iter(self.getImage())
To unpack a object, you must ensure that it is iterable:
>>> class Foo:
... def __iter__(self): return iter(range(2))
...
>>> a, b = Foo()
>>> a
0
>>> b
1
So, you should make your class iteratable:
class GetColorImage:
...
def __iter__(self):
return iter(self.getImage())
You're returning a GetColorImage object, not the two values you're actually looking for. The return statement in getImage() just returns the values to your constructor and does nothing with them. The constructor finishes and the whole GetColorImage object is returned. If you try to return something else from the constructor, you'll get an error.
You could just create the object and then call getImage():
colorObj = cratecolor.GetColorImage(ia=self.ia)
color, lightness = colorObj.getImage()
As pointed out below, you can just chain them if you don't need the object:
color, lightness = cratecolor.GetColorImage(ia=self.ia).getImage()

Loop through functions in a Class in Python

I have the following simplified code:
class States:
def __init__(self):
pass
def state1(self):
a = 2*10
return a
def state2(self):
a = 50/10
return a
class Results:
def __init__(self):
pass
def result(self):
states = States()
x = []
for i in [state1,state2]:
state_result = states.i()
x.append(state_result)
return x
I want to loop through every function in the class "States". Of course
for i in [state1,state2]
will return "name 'state1' is not defined", but I hope it gives an idea what I try to achieve.
You can use dir() to get the name of the functions of a class. You can then use getattr() to call the function.
class States:
def __init__(self):
pass
def state1(self):
a = 2*10
return a
def state2(self):
a = 50/10
return a
state = States()
for func in dir(States):
if func.startswith('__'):
continue
print(func)
print(getattr(state, func)())
Will output
state1
20
state2
5.0
You can do this tho:
def result(self):
states = States()
x = []
for i in [states.state1,states.state2]: # changed state1 to states.state1 and so on
state_result = i()
x.append(state_result)
return x
I think you can use lambda. Here, i made a simple example for you.
def foo(text):
print(text)
a = [lambda: foo("hey"), lambda: foo("boo")]
for i in a:
i()
Result:
hey
boo
In your case, you should come over with this:
for i in [lambda: state1(), lambda:state2()]:
state_result = i()
x.append(state_result)
But if you ask my opinion, it's important to inform you that calling functions through a list is not a healthy way. A software languge usually has a solution for many cases; but in this case, i think your point of view is wrong. Doing work by messing with built-in techniques and trying to find some secret tricks is is not a suggested thing.
The clean way to do this is to "register" your state methods. SOmething like this:
class States():
states = []
def register_state(cache):
def inner(fn):
cache.append(fn)
return inner
#register_state(states)
def state1(self):
a = 2*10
return a
#register_state(states)
def state2(self):
a = 50/10
return a
Then your Results class can do
class Results:
def __init__(self):
pass
def result(self):
states = States()
x = []
for i in states.states:
state_result = i(states)
x.append(state_result)
return x
You can get the members of class States via the class' dict as:
States.__dict__
Which'll give you all the attributes and function of your class as:
{'__module__': '__main__', '__init__': <function States.__init__ at 0x00000183066F0A60>, 'state1': <function States.state1 at 0x00000183066F0AF0>, 'state2': <function States.state2 at 0x000001830 ...
You can filter this into a list comprehension dict to not include dunders as:
[funcname for funcname in States.__dict__ if not (str.startswith('__') and str.endswith('__'))]
This will return you a list of member functions as:
['state1', 'state2']
Then create an object of States as:
states = States()
get the whole calculation done as:
for funcname in [funcname for funcname in States.__dict__ if not (funcname.startswith('__') and funcname.endswith('__'))]:
x.append(States.__dict__[funcname](states))
Better yet, make it a comprehension as:
[States.__dict__[funcname](states) for funcname in States.__dict__ if not (funcname.startswith('__') and funcname.endswith('__'))]
Your answer after applying this approach is: [20, 5.0]
or get the dict of functionName and returnValues as a comprehension:
{funcname: States.__dict__[funcname](states) for funcname in States.__dict__ if not (funcname.startswith('__') and funcname.endswith('__'))}
Which'll give you an output as:
{'state1': 20, 'state2': 5.0}

A python function that return a list of function with a for loop

I am trying to implement a function (make_q) that returns a list of functions(Q) that are generated using the argument that make_q gets (P). Q is a variable dependent to n(=len(P)) and making the Q functions are similar, so it can be done in a for loop but here is the catch if I name the function in the loop, they will all have the same address so I only get the last Q, Is there to bypass this?
Here is my code,
def make_q(self):
Temp_P=[p for p in self.P]
Q=()
for i in range(self.n-1):
p=min(Temp_P)
q=max(Temp_P)
index_p=Temp_P.index(p)
index_q=Temp_P.index(q)
def tempQ():
condition=random.random()
if condition<=(p*self.n):
return index_p
else:
return index_q
Temp_Q=list(Q)
Temp_Q.append(tempQ)
Q=tuple(Temp_Q)
q-=(1-p*self.n)/self.n
Temp_P[index_q]=q
Temp_P.pop(index_p)
return Q
test.Q
(<function __main__.Test.make_q.<locals>.tempQ()>,
<function __main__.Test.make_q.<locals>.tempQ()>,
<function __main__.Test.make_q.<locals>.tempQ()>,
<function __main__.Test.make_q.<locals>.tempQ()>,
<function __main__.Test.make_q.<locals>.tempQ()>)
I also tried to make them a tuple so they have different addresses but it didn't work.
Is there a way to name functions(tempQ) dynamic like tempQi
jasonharper's observation and solution in comments is correct(and should be the accepted answer). But since you asked about metaclasses, I am posting this anyway.
In python, each class is a type , with "name", "bases" (base classes) and "attrs"(all members of a class). Essentially, a metaclass defines a behaviour of a class, you can read more about it at https://www.python-course.eu/python3_metaclasses.php and various other online tutorials.
The __new__ method runs when a class is set up. Note the usage of attrs where your class member self.n is accessed by attrs['n'] (as attrs is a dict of all class members). I am defining functions tempQ_0, tempQ_1... dynamically. As you can see, we can also add docstrings to this dynamically defined class members.
import random
class MyMetaClass(type):
def __new__(cls, name, bases, attrs):
Temp_P = [p for p in attrs['P']]
for i in range(attrs['n'] - 1):
p = min(Temp_P)
q = max(Temp_P)
index_p = Temp_P.index(p)
index_q = Temp_P.index(q)
def fget(self, index_p=index_p, index_q=index_q): # this is an unbound method
condition = random.random()
return index_p if condition <= (p * self.n) else index_q
attrs['tempQ_{}'.format(i)] = property(fget, doc="""
This function returns {} or {} randomly""".format(index_p, index_q))
q -= (1 - p * attrs['n']) / attrs['n']
Temp_P[index_q] = q
Temp_P.pop(index_p)
return super(MyMetaClass, cls).__new__(cls, name, bases, attrs)
# PY2
# class MyClass(object):
# __metaclass__ = MyMetaClass
# n = 3
# P = [3, 6, 8]
# PY3
class MyClass(metaclass=MyMetaClass):
n = 3
P = [3, 6, 8]
# or use with_metaclass from future.utils for both Py2 and Py3
# print(dir(MyClass))
print(MyClass.tempQ_0, MyClass.tempQ_1)
output
<property object at 0x10e5fbd18> <property object at 0x10eaad0e8>
So your list of functions is [MyClass.tempQ_0, MyClass.tempQ_1]
Please try via formatted strings, for eg: "function_{}.format(name)" also, how do you want your output to look like?

Adding 2 python class objects together

I am having some problems adding two class objects together.
This is the code given to me, which will run MY file, the HyperLogLog and a sample text file:
import HyperLogLog
import sys
hlls = [HyperLogLog.HyperLogLog() for _ in range(5)]
with open(sys.argv[1], "r") as file:
for line in file:
cleanLine = line.replace("\n", "")
(cmd, set, value) = cleanLine.split(" ")[:3]
# See if this was an add, count, or merge command
if cmd == "A":
hlls[int(set)].add(value)
elif cmd == "C":
estimate = hlls[int(set)].count()
print("Estimate:", estimate, "Real count:", value)
elif cmd == "M":
(cmd, m1, m2, m3) = cleanLine.split(" ")
hlls[int(m3)] = hlls[int(m1)] + hlls[int(m2)]
The bottom most line is to merge hlls(set m1) and hlls(set m2). hlls(set x) stores a single parameter M, which is my HyperLogLog vector. I need to make an add function to make the addition line above work. This I have done as follows:
class HyperLogLog:
def __init__(self):
self.M = [0 for x in range(m)]
##############
Code altering the self.M
##############
def __add__(self, other):
Sum=other.M
for i,value in enumerate(other.M):
if value<self.M[i]:
Sum[i]=self.M[i]
self.M=Sum
return self
This will return the correct value for the m3 set. But it will also alter the self.M value of set m1. How can I return something other than self, which will make hlls[int(m3)] and instance of the HyperLogLog class, with the merged self.M value?
If I just return the Sum function, hlls[int(m3)] is no longer an instance of the HyperLogLog class.
If I change self.M as I do, I alter the self.M value of hlls[int(m1)].
If I do something like:
def __add__(self, other):
Sum=other.M
for i,value in enumerate(other.M):
if value<self.M[i]:
Sum[i]=self.M[i]
self2=self
self2.M=Sum
return self2
The value of self.M of instance hlls[int(m1)] is still changed. I don't understand why.
When you do this:
self2=self
Both self and self2 point to the same object, so when one is changed the other one is changed as well. The easiest fix would be to create a new HyperLogLog object, so you would replace the line above with:
self2=HyperLogLog()
This doesn't create a new object instance. It just assigns another name to the same object.
self2=self
You should create a new HyperLogLog object in the __add__ method.
Something like this:
def __add__(self, other):
retval = HyperLogLog()
retval.M = [max(a, b) for a, b in zip(self.M, other.M)]
return retval

How to use two helper functions in main script from another script

TypeError: _slow_trap_ramp() takes 1 positional argument but 2 were given
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
set_trap_ramp = InstrumentsClass.KeysightB2962A.set_trap_ramp
return set_trap_ramp
def _slow_trap_ramp(self):
slow_trap_ramp = ExperimentsSubClasses.FraunhoferAveraging.slow_trap_ramp
return slow_trap_ramp
The error is straightforward.
ramp = self._slow_trap_ramp(j)
You are calling this method with an argument j, but the method doesn't take an argument (other than self, which is used to pass the object).
Re-define your method to accept an argument if you want to pass it one:
def _slow_trap_ramp(self, j):
It looks like your code extract contains methods of some class, whose full definition is not shown, and you are calling one method from another method (self._slow_trap_ramp(j)). When you call a method, Python automatically passes self before any other arguments. So you need to change def _slow_trap_ramp(self) to def _slow_trap_ramp(self, j).
Update in response to comment
To really help, we would need to see more of the class you are writing, and also some info on the other objects you are calling. But I am going to go out on a limb and guess that your code looks something like this:
InstrumentsClass.py
class KeysightB2962A
def __init__(self):
...
def set_trap_ramp(self):
...
ExperimentsSubClasses.py
class FraunhoferAveraging
def __init__(self):
...
def slow_trap_ramp(self, j):
...
Current version of main.py
import InstrumentsClass, ExperimentsSubClasses
class MyClass
def __init__(self)
...
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
set_trap_ramp = InstrumentsClass.KeysightB2962A.set_trap_ramp
return set_trap_ramp
def _slow_trap_ramp(self):
slow_trap_ramp = ExperimentsSubClasses.FraunhoferAveraging.slow_trap_ramp
return slow_trap_ramp
if __name__ == "__main__":
my_obj = MyClass()
my_obj.demag_chip()
If this is the case, then these are the main problems:
Python passes self and j to MyClass._slow_trap_ramp, but you've only defined it to accept self (noted above),
you are using class methods from KeysightB2962A and FraunhoferAveraging directly instead of instantiating the class and using the instance's methods, and
you are returning references to the methods instead of calling the methods.
You can fix all of these by changing the code to look like this (see embedded comments):
New version of main.py
import InstrumentsClass, ExperimentsSubClasses
class MyClass
def __init__(self)
# create instances of the relevant classes (note parentheses at end)
self.keysight = InstrumentsClass.KeysightB2962A()
self.fraun_averaging = ExperimentsSubClasses.FraunhoferAveraging()
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
# call instance method (note parentheses at end)
return self.keysight.set_trap_ramp()
def _slow_trap_ramp(self, j): # accept both self and j
# call instance method (note parentheses at end)
return self.fraun_averaging.slow_trap_ramp(j)
if __name__ == "__main__":
my_obj = MyClass()
my_obj.demag_chip()

Categories