employees = []
for i in range(0,10):
emp = Employee(i)
emp.first_name = "%s-%s"%("first name", i)
emp.last_name = "%s-%s"%("last_name", i)
emp.desgination = "%s-%s"%("engineer", i)
employees.append(emp)
ids = [e.eid for e in employees]
Following is my class definition:
class Employee:
_fields = {}
def __init__(self, eid):
self.eid = eid
def __getattr__(self, name):
return self._fields.get(name)
def __setattr__(self,name,value):
self._fields[name] = value
def __str__(self):
return str(self._fields)
def __unicode__(self):
return str(self._fields)
The issue is that when I print ids, it contains 10 times 9... i.e.
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
It seems that the same emp variable is being overwritten. I am not sure what going wrong. Though I am a Java coder but I thought I had a fair idea of Python as well.
The problem is, indeed, your java past ! :)
The error is here:
_fields = {}
_fields is a CLASS member ! So each instance of Employee shares the same _fields var, and whenever you modify one, you modify all other objects.
You must move the _fields = {} part into the __init__ function :
self._fields={}
But then, you will run into another problem: self.eid = xx invokes the __setattr__ method! (and so does self._fields !)
The solution is to use self.__dict__['_fields'] when you need to access to the instance's '_fields' member instead of self._fields. It will directly access the member, instead of going through __getattr__ and an infinite reccursion, with a nice stack overflow in the end.
its a side effect of the functions:
def __getattr__(self, name):
return self._fields.get(name)
def __setattr__(self,name,value):
self._fields[name] = value
remove them and it works. so this is the direction to look.
Related
My goal is to give numpy.ndarray a different representation, since I want to represent some arrays with units. Thus, I programmed a class that inherits its attributes/ methods from numpy.ndarray. For the another representation I wanted to use the __repr__ magic method like:
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
obj = np.array(value, dtype=dtype, copy=copy, order=order,
subok=True, ndmin=ndmin).view(cls)
obj.__unit = util.def_unit(unit)
obj.__value = value
return obj
def __repr__(self):
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray),
separator=sep,
prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)
So far this works fine. However, if I want to access the inherited methods from numpy.ndarray I get a AttributeError because __repr__ cant resolve self.__unit.
I tried to solve this problem with a private method that defines the variable self.__unit and called it within the __new__ method but without success:
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
obj = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin).view(cls)
# Here I call the private method to initialize self.__unit.
obj.__set_unit()
obj.__value = value
return obj
def __repr__(self):
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray), separator=sep, prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)
# New defined private class.
def __set_unit(self, unit):
self.__unit = util.def_unit(unit)
I can not solve this with something like cls.__unit = util.def_unit(unit) in the __new__ method. I already tried to define a __init__ method after __new__. Moreover, I tried to interchange the private methods with public methods.
What I expect:
>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
<Quantitiy [[1,2,3,4],
[5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
[25,36,49,64]] meter**2/second**2>
>>> q.min()
>>> <Quantitiy 1 meter/second>
The actual result is:
>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
<Quantitiy [[1,2,3,4],
[5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
[25,36,49,64]] meter**2/second**2>
# Up to here everything works fine.
>>> q.min()
>>> AttributeError: 'Quantitiy' object has no attribute
'_Quantitiy__unit'
Does anyone see the mistake and can help me?
Ok, the answer is - as usual - in the FineManual (and could be found searching for "subclassing numpy ndarray" - which is how I found it actually), and requires implementing __array_finalize__(self, obj) :
import numpy as np
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
x = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin)
obj = x.view(type=cls)
obj._unit = unit
obj._value = value
return obj
def __repr__(self):
print("repr %s" % type(self))
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray),
separator=sep,
prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self._unit)
def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments
if obj is None:
return
self._unit = getattr(obj, '_unit', None)
self._value = getattr(obj, '_value', None)
So I have this class:
#!/usr/bin/python3
class MyClass(object):
def __init__(self, length):
self._list = length
def get(self, index):
try:
return self._list[index]
except IndexError:
return None
which takes in a list and returns a value, a list index I think. I am trying to get that value:
def my_function(a_list):
a_list = MyClass
for x in (10**p for p in range(1, 9)):
if a_list:
print(a_list)
def main():
length = my_function(MyClass([i for i in range(0, 543)]))
but I keep getting only the memory location of the list, I think this is supposed to return an int.
I am hoping this is a workable bit of code, but I am struggling, with the concept of passing an "object" to a class, it doesn't make any sense to me.
Here is a test I am supposed to use:
def test_large_list():
s_list = My_Class([i for i in xrange(0, 100000)])
assert len(s_list._list) == list_length(s_list)
Ok, Here is my full function that works, it is done, how od I do this so that the first line takes an argument
#!/usr/bin/python3
#def list_length(single_method_list): This is what I am supposed to work with
from single_method_list import SingleMethodList
def my_function(): # This is how I have done it and it works.
a_list = MyClass([i for i in range(0, 234589)])
for x in (10**p for p in range(1, 8)):
if a_list.get(x):
print("More than", x)
first = x
else:
print("Less than", x)
last = x
break
answer = False
while not answer:
result = (first + last)/2
result = int(round(result))
print(result)
if s_list.get(result):
first = result
print('first', result)
else:
last = result
print('last', result)
if s_list.get(result) and not s_list.get(result + 1):
answer = True
print(result + 1)
my_function()
I don't know what more I can give to explain where I am stuck, it is the OOP part of this that I don't know I need the same results here, just passing it to the function instead of creating it inside the function which I did in order to do the algorithm.
Well your class does something else.MyClass is designed to take a List at initialization, so the naming length is not a good idea.
The get() method of this class takes in a number and returns the element located at that particular index in the initialized self._list.
Your logic should be like:
def my_function(a_list):
a_list = MyClass(a_list)
...
def main():
length = my_function([i for i in range(0, 543)])
Just to clarify some misunderstanding that you might have.
Class does not return anything. It is a blueprint for creating objects.
What can return value is a method (function). For instance, if you want to write a method which returns length of some list:
def my_function(some_list):
return len(some_list)
Or in your case:
def my_function(a_list):
return len(a_list._list)
Note that you should not call your variables list. It's a built-in function in python which creates lists.
And as you can see there is another built-in function len in python which returns length of list, tuple, dictionary etc.
Hope this helps, although it's still a bit unclear what you're trying to achieve.
How do I change the code so that it would return a is a square with side:5 and area:25 ?? when I call print a?
class Square():
def __init__(self, length):
self.length = length
def area(self):
return self.length ** 2
def __str__(self): #this is the part I don't know how to write
return "is a square with side:%s and area:%s." % (self.length, self.area())
a = Square(5)
print a
I guess you want to get the name of the variable that you asign with your class, right??
I don't know how to do that or is that is posible (or usefull in any way) because you can have have multiples variables pointing to the same object
for example in this
a=SomeObject()
b=a
c=a
d=c
and in this case how you will know which one you are using if all of them point to the same object?
A alternative is give your class a extra paremetrer with the name that you wish for you instance
class Square():
def __init__(self, length,name=""):
self.length = length
self.name = name
def area(self):
return self.length ** 2
def __str__(self): #this is the part I don't know how to write
return "%s is a square with side:%s and area:%s." % (self.name, self.length, self.area())
a = Square(5,'MySquare')
print a # MySquare is a square with side:5 and area:25.
I have a Restaurant and Dish type namedtuple defined below:
Restaurant = namedtuple('Restaurant', 'name cuisine phone menu')
Dish = namedtuple('Dish', 'name price calories')
r1 = Restaurant('Thai Dishes', 'Thai', '334-4433', [Dish('Mee Krob', 12.50, 500),
Dish('Larb Gai', 11.00, 450)])
I need to change the price of the dish by 2.50. I have the following code:
def Restaurant_raise_prices(rest):
result = []
for item in rest:
for dish in item.menu:
dish = dish._replace(price = dish.price + 2.50)
result.append(item)
return result
It replaces the price field and returns the Dish namedtuple:
[Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)]
How can I change my code to add the restaurant as well?
but it only returns the Dish. What if I wanted the entire Restaurant too? How can I make the change so that the output is:
Restaurant('Thai Dishes', 'Thai', '334-4433', [Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)])
Named tuples are first and foremost tuples, and as such immutable. That means that you cannot modify the existing objects. If you wanted to change them, you would have to create new tuples containing the new values and replace all references to the old tuple with that new tuple.
The code you are using does not work for that, since dish = dish._replace(…) will replace the value of dish with a new tuple, but changing what dish references will not update the reference that exists within the restaurant tuple. Also, with the line result.append(item) being part of the inner loop where you iterate over the dishes, you end up with multiple (unchanged!) copies of the same restaurant tuple in the result.
You could change it like this to make it work (btw. assuming you only pass a single restaurant to the function—so you only need one loop for the dishes):
def restaurant_raise_prices (rest):
dishes = []
for dish in rest.menu:
dishes.append(dish._replace(price=dish.price + 2.50))
rest = rest._replace(menu=dishes)
return rest
This will return a new restaurant with the changed prices for each dish (note that r1 won’t reflect this change):
>>> r1
Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450)])
>>> restaurant_raise_prices(r1)
Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)])
A cleaner way however would be to introduce proper types that are mutable, so you can make this a bit better. After all, restaurants are objects that can change: They can modify their menu all the time, without becoming a new restaurant. So it makes sense to have the restaurants—as well as the dishes—be mutable objects instead:
class Restaurant:
def __init__ (self, name, cuisine, phone):
self.name = name
self.cuisine = cuisine
self.phone = phone
self.menu = []
def __str__ (self):
return '{} ({}) - {} ({} dishes)'.format(self.name, self.cuisine, self.phone, len(self.menu))
class Dish:
def __init__ (self, name, price, calories):
self.name = name
self.price = price
self.calories = calories
def raise_price (self, amount):
self.price += amount
def __str__ (self):
return '{} (price: {}, calories: {})'.format(self.name, self.price, self.calories)
>>> r1 = Restaurant('Thai Dishes', 'Thai', '334-4433')
>>> r1.menu.append(Dish('Mee Krob', 12.50, 500))
>>> r1.menu.append(Dish('Larb Gai', 11.00, 450))
>>> print(r1)
Thai Dishes (Thai) - 334-4433 (2 dishes)
>>> for dish in r1.menu:
print(dish)
Mee Krob (price: 12.5, calories: 500)
Larb Gai (price: 11.0, calories: 450)
>>> for dish in r1.menu:
dish.raise_price(2.50)
print(dish)
Mee Krob (price: 15.0, calories: 500)
Larb Gai (price: 13.5, calories: 450)
recently I've started to use the excellent boost::unordered_map on my system, but got one drawback: I couldn't figure how to inspect its contents. Printing it on gdb gives me a table_ and a buckets_, but haven't found where are the items. Anyone has a clue about this?
For the ones that wanted a printer, I've managed to create one. Here is Code:
class BoostUnorderedMapPrinter:
"prints a boost::unordered_map"
class _iterator:
def __init__ (self, fields):
type_1 = fields.val.type.template_argument(0)
type_2 = fields.val.type.template_argument(1)
self.buckets = fields.val['table_']['buckets_']
self.bucket_count = fields.val['table_']['bucket_count_']
self.current_bucket = 0
pair = "std::pair<%s const, %s>" % (type_1, type_2)
self.pair_pointer = gdb.lookup_type(pair).pointer()
self.base_pointer = gdb.lookup_type("boost::unordered_detail::value_base< %s >" % pair).pointer()
self.node_pointer = gdb.lookup_type("boost::unordered_detail::hash_node<std::allocator< %s >, boost::unordered_detail::ungrouped>" % pair).pointer()
self.node = self.buckets[self.current_bucket]['next_']
def __iter__(self):
return self
def next(self):
while not self.node:
self.current_bucket = self.current_bucket + 1
if self.current_bucket >= self.bucket_count:
raise StopIteration
self.node = self.buckets[self.current_bucket]['next_']
iterator = self.node.cast(self.node_pointer).cast(self.base_pointer).cast(self.pair_pointer).dereference()
self.node = self.node['next_']
return ('%s' % iterator['first'], iterator['second'])
def __init__(self, val):
self.val = val
def children(self):
return self._iterator(self)
def to_string(self):
return "boost::unordered_map"
In a typical hash table implementation, the buckets contain the head of a linked list which actually contains the values corresponding to this particular hash. Thus I would bet on buckets_.
Another option: there are various python pretty printer libraries for gdb now, and I think that you could find one that works with C++0x and inspect where it looks for the values.