I'm looking over someone else's code trying to learn from them and I have a question on something they've done.
This is line 16 from the link
self.sentence = sentence or ""
What does or in the assignment operator do?
I've tried running this myself and if sentence is defined then the it's assigned to self.sentence, otherwise if it's not assigned I get a NameError exception.
https://github.com/xavier/exercism-assignments/blob/master/python/bob/bob.py
or is a lazy operator, and returns first value, which is 'trueish' (bool(value) is True). This idiom is used, to assign a value, or if it is empty, something else.
In this case, probably it guards against assigning None, which evaluates to False, but author wanted to be sure, that be always a string will be assigned - and empty string in this case.
In the sample code, this would make more sense if __init__() had a default argument:
class Fake:
def __init__(self, sentence=None):
self.sentence = sentence or '<empty>'
def print_me(self):
print(self.sentence)
a = Fake('A real sentence')
b = Fake()
a.print_me()
b.print_me()
outputs:
paul#local:~/src/sandbox$ ./def.py
A real sentence
<empty>
paul#local:~/src/sandbox$
In this particular case, def __init__(self, sentence='<empty>'): followed by self.sentence = sentence would have done equally well, but this could be more useful when dealing with mutable objects such as lists, since def __init__(self, sentence=[]): will evaluate only once, and all the classes would refer to the same default list. Specifying None as the default value instead, and creating a separate empty list in __init__() would avoid this behavior.
For instance:
#!/usr/bin/env python
class Weird:
def __init__(self, the_list=[]): # <--- Don't do this
self.the_list = the_list
def append(self, value):
self.the_list.append(value)
def print_me(self):
print(self.the_list)
class Normal:
def __init__(self, the_list=None):
self.the_list = the_list or []
def append(self, value):
self.the_list.append(value)
def print_me(self):
print(self.the_list)
print("Weird output:")
a = Weird()
b = Weird()
a.append(1)
a.append(2)
a.print_me()
b.print_me()
print("Normal output:")
c = Normal()
d = Normal()
c.append(1)
c.append(2)
c.print_me()
d.print_me()
outputs:
paul#local:~/src/sandbox$ ./def2.py
Weird output:
[1, 2]
[1, 2]
Normal output:
[1, 2]
[]
paul#local:~/src/sandbox$
In the first case, you might expect each object to get its own empty list, but you can see when you append things to a, they get appended to b also, because a and b are sharing the same list. This is not happening in the second case, because we specified the default as None rather than [], and then used the idiom in your question. When the_list is None, the_list or [] will evaluate to []. When it's not, it'll just evaluate to the_list. It's equivalent to:
if sentence:
self.sentence = sentence
else:
self.sentence = ""
Related
How could I recursively iterate through nodes with reference to a previous node? Expecting output 4,3,2,1 in the example below:
class Node:
def __init__(self, parent, value):
self.parent = parent
self.value = value
def append(self, value):
return Node(self, value)
def list(l):
print(l.value)
while l.parent is not None:
list(l.parent)
l = Node(None, 1)
l = l.append(2)
l = l.append(3)
l = l.append(4)
list(l)
Your class structure already succesfully passes the node's self value to its child node. The problem is your list function. while l.parent is not None: never ends, because nothing in the loop is changing the value of l. Calling list recursively will create a new context where another variable named l has a different value from the first context's l, but this has no effect on the the first l or the first loop. Recursive functions generally do not require an actual loop in order to iterate over the elements of a data structure. Try:
def list(l):
print(l.value)
if l.parent is not None:
list(l.parent)
Or:
def list(l):
while l is not None:
print(l.value)
l = l.parent
(I recommend the latter because the first one will crash with "maximum recursion depth exceeded" if the chain has more than 999 elements)
Result:
4
3
2
1
Bonus style tip: consider naming your function something other than list. In general you should avoid overwriting the names of built-in functions and types.
I should vote to close your question for the lack of a clear problem statement, but anyway...
Within an object in Python, how can I pass a reference of my current object
The same way as you'd do with just any object.
to object b of the same class
This is actually irrelevant but anyway...
such that when I call b.parent, I can get back to object a?
class Foo(object):
def __init__(self, parent=None):
self.parent = parent
a = Foo()
b = Foo(a)
print(b.parent is a)
Now for the answer to the question you didn't ask, see (and accept) Kevin's answer ;-)
What does the obj=lists[0] do in the following code?
lists = []
infile = open(path, 'rb')
while True:
try:
lists.append(pickle.load(infile))
except EOFError:
break
obj=lists[0]
while len(lists) > 3:
lists.pop(0)
print(lists)
infile.close()
I have tried to understand it but I cannot seem to see any reason for it.
Nothing.
obj is never referred to after its initial assignment, so it has no effect on anything.
The only possible way I could see that line doing anything, is if lists was some strange class whose __getitem__ call has a side effect. For example,
class StrangeList(list):
def __getitem__(self, idx):
self[idx] = 23
return 23
def a():
x = StrangeList([1,2,3])
print x
def b():
x = StrangeList([1,2,3])
obj = x[0]
print x
print "Calling a"
a()
print "Calling b"
b()
Result
Calling a
[1, 2, 3]
Calling b
[23, 2, 3]
Here, doing obj = x[0] does do something, even though obj is never used. But this is a contrived example; for your current code and for 99.9% of the classes you're likely to use in the future, __getitem__ won't behave this way.
Assuming this is all the code there is, there is no use for it and, as #Daniel Roseman mentioned, it must be a left over from some refactoring.
If there is more code in your program, I would suggest that the variable obj is being used to preserve the first value of the list. The loop below it consumes all elements in the list (except the last three), so if you are going to need the original first object in the list, you need to preserve it - hence, the obj attribution.
Apologies if someone has already addressed this, but I couldn't find an answer.
I have a problem where I overrode __cmp__ for a custom class, similar to this:
class MyClass(object):
def __init__(self, prop):
self.prop = prop
def __cmp__(self, other):
return cmp(self.prop, other.prop)
a = MyClass(1)
b = MyClass(2)
c = MyClass(3)
d = MyClass(1)
my_list = [a, b, c]
print a in my_list
print b in my_list
print c in my_list
print d in my_list
# Output:
#
# True
# True
# True
# True
Reading the docs tells me that this is expected, because:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
My question is two-fold:
Why does Python (2.7) use == rather than is to test list membership?
Is there a better way to be doing this, such that I can test whether a specific instance of my class is actually in a container and be able to compare instances based on their attributes?
Why does Python (2.7) use == rather than is to test list membership?
Because equality is usually more interesting than identity for containment checking, especially when two different objects can have the same value.
>>> ('Hello, ' + 'world!') is 'Hello, world!'
False
>>> ('Hello, ' + 'world!') == 'Hello, world!'
True
Is there a better way to be doing this, such that I can test whether a specific instance of my class is actually in a container and be able to compare instances based on their attributes?
Not especially.
The list contains a value equal to the variable, not a reference to the variable. Think about it this way. Are these two code samples the same? What makes them different?
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
# sample one
sam = Person('Sam')
bob = Person('Bob')
people = [sam, bob]
The first sample is when you should use the is keyword. You're trying to test if the object in the list is the object outside of the list, meaning the sam inside the list is stored in the same place in memory as the sam outside the list.
# sample two
sam = Person('Sam')
bob = Person('Bob')
people = [Person('Sam'), Person('Bob')]
This sample is when you should use the double equals keyword. You're trying to test if the object in the list has the value when compared to the object outside of the list. Notice, that because we instantiated to different people with the name Sam, they will be equal in value but not the same object.
[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)
I'm sure there is a term for what I'm looking for, or if there's not, there is a very good reason what I'm trying to do is in fact silly.
But anyway. I'm wondering whether there is a (quasi) built-in way of finding a certain class instance that has a property set to a certain value.
An example:
class Klass(object):
def __init__(self, value):
self.value = value
def square_value(self):
return self.value * self.value
>>> a = Klass(1)
>>> b = Klass(2)
>>> instance = find_instance([a, b], value=1)
>>> instance.square_value()
1
>>> instance = find_instance([a, b], value=2)
>>> instance.square_value()
4
I know that I could write a function that loops through all Klass instances, and returns the ones with the requested values. On the other hand, this functionality feels as if it should exist within Python already, and if it's not, that there must be a very good reasons why it's not. In other words, that what I'm trying to do here can be done in a much better way.
(And of course, I'm not looking for a way to square a value. The above is just an example of the construct I'm trying to look for).
Use filter:
filter(lambda obj: obj.value == 1, [a, b])
Filter will return a list of objects which meet the requirement you specify. Docs: http://docs.python.org/library/functions.html#filter
Bascially, filter(fn, list) iterates over list, and applies fn to each item. It collects all of the items for which fn returns true, puts then into a list, and returns them.
NB: filter will always return a list, even if there is only one object which matches. So if you only wanted to return the first instance which matches, you'd have to to something like:
def find_instance(fn, objs):
all_matches = filter(fn, objs)
if len(all_matches) == 0:
return False # no matches
else:
return all_matches[0]
or, better yet,
def find_instance(fn, objs):
all_matches = filter(fn, objs)
return len(all_matches) > 0 and all_matches[0] # uses the fact that 'and' returns its second argument if its first argument evaluates to True.
Then, you would call this function like this:
instance = find_instance(lambda x: x.value == 1, [a, b])
and then instance would be a.
A more efficient version of Ord's answer, if you are looking for just one matching instance, would be
def find_instance(fn, objs):
all_matches = (o for o in objs if fn(objs))
return next(all_matches, None)
instance = find_instance(lambda x: x.value == 1, [a, b])
This will stop the search as soon as you find the first match (good if your test function is expensive or your list is large), or None if there aren't any matches.
Note that the next function is new in Python 2.6; in an older version, I think you have to do
try:
return all_matches.next()
except StopIteration:
return None
Of course, if you're just doing this once, you could do it as a one-liner:
instance = next((o for o in [a, b] if o.value == 1), None)
The latter has the advantage of not doing a bunch of function calls and so might be slightly faster, though the difference will probably be trivial.