Iterating through a dictionary of a class object without mixin - python - python

The main function of the class is a dictionary with words as keys and id numbers as values (note: id is not in sequential because some of the entries are removed):
x = {'foo':0, 'bar':1, 'king':3}
When i wrote the iterator function for a customdict class i created, it breaks when iterating through range(1 to infinity) because of a KeyError.
class customdict():
def __init__(self,dic):
self.cdict = dic
self.inverse = {}
def keys(self):
# this is necessary when i try to overload the UserDict.Mixin
return self.cdict.values()
def __getitem__(self, valueid):
""" Iterator function of the inversed dictionary """
if self.inverse == {}:
self.inverse = {v:k for k,v in self.cdict.items()}
return self.inverse[valueid]
x = {'foo':0, 'bar':1, 'king':3}
y = customdict(x)
for i in y:
print i
Without try and except and accessing the len(x), how could I resolve the iteration of the dictionary within the customdict class? Reason being x is >>>, len(x) will take too long for realtime.
I've tried UserDict.DictMixin and suddenly it works, why is that so?:
import UserDict.DictMixin
class customdict(UserDict.DictMixin):
...
Is there a way so that i don't use Mixin because somehow in __future__ and python3, mixins looks like it's deprecated?

Define following method.
def __iter__(self):
for k in self.keys():
yield k
I've tried UserDict.DictMixin and suddenly it works, why is that so?:
Because DictMixin define above __iter__ method for you.
(UserDict.py source code.)

Just share another way:
class customdict(dict):
def __init__(self,dic):
dict.__init__(self,{v:k for k,v in dic.items()})
x = {'foo':0, 'bar':1, 'king':3}
y = customdict(x)
for i in y:
print i,y[i]
result:
0 foo
1 bar
3 king

def __iter__(self):
return iter(self.cdict.itervalues())
In Python3 you'd call values() instead.
You're correct that UserDict.DictMixin is out of date, but it's not the fact that it's a mixin that's the problem, it's the fact that collections.Mapping and collections.MutableMapping use a more sensible underlying interface. So if you want to update from UserDict.DictMixin, you should switch to collections.Mapping and implement __iter__() and __len__() instead of keys().

Related

Decorate a class with Python that prints the int variables of the decorated class

I'm studying for a python course and one of the exercise was to create a decorator for this class that returns every int variables.`
#decoratoreDiClasse
class MyClass:
def __init__(self):
self.a = 1
self.b = 2
self.c = 'w'`
My problem is that the list is always empty beacuse dict does not return the variables inside init,how can i solve my problem?
i've written my decorator below
def decoratoreDiClasse(cls):
def elencaVariabili():
lista = []
print(cls)
lista1 = cls.__dict__
print(lista1)
for ab in lista1:
if isinstance(ab, int):
lista.append(ab)
return lista
setattr(cls, "elencaVariabili", elencaVariabili())
return cls
here's the part of the main that should print the variables,I cannot change anything apart from "decoratoreDiClasse" due to the teacher request.
for v in x.elencaVariabili():
print(v, end=' ')
It looks like you're supposed to have your decorator add a method to the class that prints out integer-valued attributes on an instance it's called on. That's not what you're currently trying to do, as your code tries to find the variables on the class instead of on an instance later on.
Think of what you're doing as a method, and it will be a lot simpler:
def decoratoreDiClasse(cls):
def elencaVariabili(self): # this is a method, so it should take self!
lista = [value for value in self.__dict__.values() # loop over our attribute values
if isinstance(value, int)] # and pick out the integers!
return lista
setattr(cls, "elencaVariabili", elencaVariabili) # don't call the method here
return cls
It's not entirely clear from your code if you're supposed to be returning the names of the integer variables or just the values themselves. I went with just the values, but if you need the variable names, you may need to change the list comprehension to iterate over the items() of the instance's dictionary rather than just the values().

Is there an accepted way to have a function pop a value from a parameter?

Essentially, I would like to know if I should be attempting to avoid side effects in functions if possible, or if side effects are acceptable in certain situations. I would like to have a function which pops and returns a key from a dictionary and am curious if the function should return just the key:
def popkey(d):
k, v = d.popitem()
return k
mykey = popkey(d)
or if it should also return the modified dictionary:
def popkey(d):
k, v = d.popitem()
return k, d
mykey, d = popkey(d)
More specifically, I have something like the following, where I need keep looking through the dictionary, so I wanted to pop the keys as they are paired with the elements from a list.
def pop_nearest(d, pt):
"""Pops the key in `d` which is nearest to pt."""
to_pop = min(d.iterkeys(), key=lambda a: abs(a - pt))
d.pop(to_pop)
pts = [1,3,5,7,9]
for pt in pts:
nearest_pt = pop_nearest(d, pt)
# do some other stuff
There is no need to return the parameter, since you already have a reference to it at the call site.
If you choose to implement pop_nearest as a method in a dict subclass, then it's sometimes a good idea (depending on what you are trying to achieve) to return self so you can chain calls.
class MyDict(dict):
...
def pop_nearest(self, pt):
...
return self
...
x = mydict.pop_nearest(1).pop_nearest(2)
You don't need to return the modified dictionary. It is modified in the function like you would think since it is a reference/pointer to the actual object and not a deep copy and will exist in its modified form in the calling function after pop is called. Returning the key should be sufficient and work how you want it to.

design recommendation: control flow based on argument type in Python?

I am writing a function of the form:
def fn(adict, b):
"""`adict` contains key(str): value(list). if `b` is a dict we have to
call `do_something` for pairs of lists from `adict` and `b` for
matching keys. if `b` is a list, we have to call `do_something`
for all lists in `adict` with `b` as the common second
argument.
"""
if isinstance(b, dict):
for key, value in adict.items():
do_something(value, b[key])
else:
for key, value in adict.items():
do_something(value, b)
def do_something(x, y):
"""x and y are lists"""
pass
I am aware that this may not be a good design (Is it bad design to base control flow/conditionals around an object's class?). But writing two functions, one taking b as a dict and another as a list, seems too redundant. What are some better alternatives?
There's indeed a pattern for such problems, it's named "multiple dispatch" or "multimethods". You can find a (quite simple) example Python implementation here http://www.artima.com/weblogs/viewpost.jsp?thread=101605
Using this solution, your code might look like:
from mm import multimethod
#multimethod(list, dict)
def itersources(sources, samples):
for key, value in sources.iteritems():
yield value, samples[key]
#multimethod(list, list)
def itersources(sources, samples):
for key, value in sources.iteritems():
yield value, samples
def fn(sources, samples):
for value1, value2 in itersources(sources, samples):
do_something_with(value1, value2)
I use a "switch" method for this:
class Demo(object):
def f(self, a):
name = 'f_%s' % type(a).__name__
m = getattr(self, name)
m(a)
def f_dict(self, a):
...
The code creates a method name from the type of the argument, then looks up the method in self and then calls it.

Returning an lvalue from a function in python

[Sorry, I'm new in Python. Although it seems to be a very basic question, I did my share of due diligence before asking this audience, trying to avoid really stupid questions].
I'm trying to figure out the correct idiom for returning an l-value from a function. Assume I've a container of 64 objects, and I want to be able to return a reference to these objects.
class ChessBoard:
def __init__(self):
self.squares = [None for x in range(64)]
square( row, col ):
return self.squares(row*8+col) <---- I'd like this to be l-value
Then, from outside the class I want to:
board = ChessBoard()
board.square(0,0) = Piece( Shapes.ROOK, Colors.White ) <-- I'm getting an error here
board.square(0,1) = Piece( Shapes.BISHOP, Colors.White )
... etc.
So, I would like the function 'at' to return a lvalue (Something like a reference in C++), but I can't find anything resembling a reference or a pointer in the language. If I stored a list in each square containing one Piece, it is possible I could do something like: board.square(0,0)[0] = Piece - but it seems crazy (or maybe not - as I said, I'm new to the language).
How would you approach this data structure?
In Python, everything is a reference. The only problem is that None is immutable, so you can't use the returned reference to change the value.
You also can't override the assignment operator, so you won't get this particular kind of behaviour. However, a good and very flexible solution would be to override the __setitem__ and __getitem__ methods to implement the subscription operator ([]) for the class:
class ChessBoard(object):
def __init__(self):
self.squares = [None] * 64
def __setitem__(self, key, value):
row, col = key
self.squares[row*8 + col] = value
def __getitem__(self, key):
row, col = key
return self.squares[row*8 + col]
Usage:
>>> c = ChessBoard()
>>> c[1,2] = 5
>>> c[1,2]
5
You can try something like this, at the cost of having to put bogus [:] indexers around:
class Board:
def __init__(self):
self.squares=[None for x in range(64)]
def square(self, row, col):
squares=self.squares
class Prox:
def __getitem__(self, i):
return squares[row*8+col]
def __setitem__(self, i, v):
squares[row*8+col]=v
return Prox()
Then you can do
b=Board()
b.square(2,3)[:]=Piece('Knight')
if b.square(x,y)[:] == Piece('King') ...
And so on. It doesn't actually matter what you put in the []s, it just has to be something.
(Got the idea from the Proxies Perl6 uses to do this)
As Niklas points out, you can't return an l-value.
However, in addition to overriding subscription, you can also use properties (an application of descriptors: http://docs.python.org/howto/descriptor.html) to create an object attribute, which when read from, or assigned to, runs code.
(Not answering your question in the title, but your "How would you approach this data structure?" question:) A more pythonic solution for your data structure would be using a list of lists:
# define a function that generates an empty chess board
make_chess_board = lambda : [[None for x in xrange(8)] for y in xrange(8)]
# grab an instance
b = make_chess_board()
# play the game!
b[0][0] = Piece(Shapes.ROOK, Colors.White)
b[0][1] = Piece(Shapes.BISHOP, Colors.White)
# Or use tuples:
b[0][0] = (Shapes.ROOK, Colors.White)
b[0][1] = (Shapes.BISHOP, Colors.White)

Indexer with two keys in python

I'm newbie with python. I want to write a class with two keys as indexer. also need to be able to use them inside of class like this:
a = Cartesian(-10,-10,10,10) # Cartesian is the name of my class
a[-5][-1]=10
and in the Cartesian class:
def fill(self,value):
self[x][y] = x*y-value
I try with
def __getitem__(self,x,y):
return self.data[x-self.dx][y-self.dy]
but doesn't work.
If you just need a lightweight application, you can have __getitem__ accept a tuple:
def __getitem__(self, c):
x, y = c
return self.data[x-self.dx][y-self.dy]
def __setitem__(self, c, v):
x, y = c
self.data[x-self.dx][y-self.dy] = v
and use like this:
a[-5,-1] = 10
However, if you are doing a lot of numeric computation or this is integral to your application, consider using Numpy and just represent this coordinate as a vector: Link
Is there any reason you actually need to explicitly define a Cartesian() class? For example, are there calculation methods on it? If not, then just use a lists within lists to use this type of syntax.
If you do need a class, then consider adding a .coordinate(x, y) method to it instead and don't bother trying to do the list syntax.
Accept a tuple:
>>> class Foo(object):
... def __getitem__(self, key):
... x, y = key
... print x, y
... f = Foo()
... f[1,2]
1 2

Categories