Can you please clarify how it is that self.add(x) below works the same way as self.data.append(x)?
That is, how does self.add(x) know to append to the list because we have not explicitly stated self.data.add(x)? When we state y.addtwice('cat'), 'cat' is added to 'self', not self.data.
class Bag:
def __init__(self):
self.data=[]
def add(self,x):
self.data.append(x)
return self.data
def addtwice(self,x):
self.add(x)
self.add(x)
return self.data
>>> y = Bag()
>>> y.add('dog')
['dog']
>>> y.addtwice('cat')
['dog', 'cat', 'cat']
Because addtwice calls methods which are defined on self, and because self.data is a "mutable type", addtwice's call to add will end up appending the value of self.data. add, in turn calls self.data.append
When calling a function in a computer program, you can think of the process as being a series of substitutions like this:
# -> means (substitution for)
# <= means "return"
y = Bag()
y.add('dog') ->
y.data.append(x) ->
#(machine code)
<= y.data
# at this point, at the command propmt, python will just print what was returned.
y.addtwice('cat')->
y.add('cat')->
y.data.append(x) ->
#(machine code)
<= y.data
#nothing cares about this return
y.add('cat')->
y.data.append(x) ->
#(machine code)
<= y.data
#nothing cares about this return either
<= y.data
# at this point, at the command propmt, python will just print what was returned.
self, itself, is never really appended in any of those cases though. self.data is.
self.add(x) calls the instance method add which in turn calls self.data.append(x)
When we state y.addtwice('cat'), 'cat' is added to 'self', not self.data
This is incorrect. cat is in fact added to self.data. Why would you think it was added to self?
y.add('dog') is the same as doing Bag.add(y, 'dog'). So add is really doing y.data.append('dog'), it's customary to use the name self instead.
y.addtwice('cat') is the same as doing Bag.addtwice(y, 'cat'). So addtwice is really doing y.add('cat') twice, which is the same as doing Bag.add(y, 'cat') twice. So addtwice is really doing y.data.append('cat') twice.
The self in each instance method is just an automatically added variable pointing to the instance it's called on, in this case y.
Let look at function add(self, x) from class Bag.
When that function is called, one of the parameter is self, which is the object itself, in this case, the same instance of Bag whose add function is called.
Therefore, in function add, calling self.data.append(x) is basically calling function append on data list of Bag, thus, adding the element x into the list.
Same thing for function addtwice. By calling function add twice, two elements are added into data list of Bag.
Both functions return the data list.
add(self, x) is just a function that you want to call.
append is a built in function that adds an element to the list.
so your add function basically uses append to add the element you want to the list and return the list you named data
self.addtwice will call self.add exactly two times and so will add the element twice.
Related
I have created a class and am attempting to create a function that will, in essence, act as a binary operator between two objects of that class. The function I was trying to create is called 'combine'.
I know I could create the function outside of the class, but I want it to be associated with the class.
Background (not really necessary for answering the question) - the class is modelling the S4 mathematical group and is some practice with objects and classes for me. My next function was to be to simplify an element into it's simplest expression in cycles, which I am confident that I could do, but I would rather get this one sorted first.
When I create a function with one argument, it runs fine - as demonstrated in the code below, with the function 'cycletype', which works as expected.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(first, second):
for i in second:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
print(combine(double,triple))
I was expecting [[1,2],[3,4],[1,2,3]] to be printed, however, it showed a NameError, not recognising combine.
You should be creating a new instance from the lists wrapped by the two arguments:
class S4:
# Define an element of S4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, first, second):
return S4(first.element_list + second.element_list)
It also appears that you could simply define __add__ instead of combine,
# Simplified implementation, no error checking
def __add__(self, second):
return S4(self.element_list + second.element_list)
allowing you to write
print(double + triple)
instead of
print(combine(double, triple))
There's two problems with the code
putting the function inside the class means that it's a method. So, you have to access it using the object s4.combine(s1), not just combine(...). Otherwise, it would be a function, not a method.
After you change that: you can't write for i in second, because instances of your class are not iterable. You have to implement __iter__ to be able to use that syntax
This is because the combine function isn't present in the global scope ( I hope that's what its called, I mess up names real bad).
You can only call functions present in the global scope, in the case of classes, you need objects to call these functions as these functions are part of those specific classes and not the global scope in general.
Hope this helped
There's a scope problem, you defined combine within the s4 class, so you should call it from a instance of s4. Anyways, here's is how I would do it.
class s4:
# Define an element of s4, elementlist is a nested list, which is a list of the cycles composing the element.
def __init__(self, elementlist):
self.elementlist = elementlist
# One simple function is to ascertain the cycletype of the element.
def cycletype(self):
cycles = []
for i in self.elementlist:
cycles.append(len(i))
return cycles
# Combining two elements using the group operation is the first function to define.
def combine(self, second):
#Here I changed first to self, first would be the s4 class that calls the function, in this example double and second would be the one that you want to combine
first = self.elementlist
for i in second.elementlist:
first.append(i)
return first
double = s4([[1,2],[3,4]])
triple = s4([[1,2,3]])
##As double() is defined within the s4 class, you can only call it from an instance of s4 (in this case you could use doble.combine() or triple.combine())
print(double.combine(triple))
Hope it helps.
I have a class (list of dicts) and I want it to sort itself:
class Table(list):
…
def sort (self, in_col_name):
self = Table(sorted(self, key=lambda x: x[in_col_name]))
but it doesn't work at all. Why? How to avoid it? Except for sorting it externally, like:
new_table = Table(sorted(old_table, key=lambda x: x['col_name'])
Isn't it possible to manipulate the object itself? It's more meaningful to have:
class Table(list):
pass
than:
class Table(object):
l = []
…
def sort (self, in_col_name):
self.l = sorted(self.l, key=lambda x: x[in_col_name])
which, I think, works.
And in general, isn't there any way in Python which an object is able to change itself (not only an instance variable)?
You can't re-assign to self from within a method and expect it to change external references to the object.
self is just an argument that is passed to your function. It's a name that points to the instance the method was called on. "Assigning to self" is equivalent to:
def fn(a):
a = 2
a = 1
fn(a)
# a is still equal to 1
Assigning to self changes what the self name points to (from one Table instance to a new Table instance here). But that's it. It just changes the name (in the scope of your method), and does affect not the underlying object, nor other names (references) that point to it.
Just sort in place using list.sort:
def sort(self, in_col_name):
super(Table, self).sort(key=lambda x: x[in_col_name])
Python is pass by value, always. This means that assigning to a parameter will never have an effect on the outside of the function. self is just the name you chose for one of the parameters.
I was intrigued by this question because I had never thought about this. I looked for the list.sort code, to see how it's done there, but apparently it's in C. I think I see where you're getting at; what if there is no super method to invoke? Then you can do something like this:
class Table(list):
def pop_n(self, n):
for _ in range(n):
self.pop()
>>> a = Table(range(10))
>>> a.pop_n(3)
>>> print a
[0, 1, 2, 3, 4, 5, 6]
You can call self's methods, do index assignments to self and whatever else is implemented in its class (or that you implement yourself).
I'm getting a Can't set attribute error when I'm using the += operator on a read-only property that is of a type for which I've defined a __iadd__() method.
Simplified (but runnable) version of my code:
class Emitter(list):
def __iadd__(self, other):
self.append( other )
return self
class Widget:
def __init__(self):
self._on_mouseenter = Emitter()
#property
def on_mouseenter(self): return self._on_mouseenter
my_widget = Widget()
my_widget.on_mouseenter += lambda source: print("on_mouseenter!")
The last line produces the error. It goes away if I add the following line to the definition of Widget:
#on_mouseenter.setter
def on_mouseenter(self, value): pass
(Runnable at https://repl.it/EONf/0)
This behaviour seems strange on two accounts. First, I thought that Python passes objects by reference, so why should the property have to be readable? And second, how come that my dummy setter even works?
__iadd__ returns a replacement object to be rebound to the variable. This of course requires a setter.
In this case it works because you're ignoring the set, but still leaving the original object in place, which you've changed in place.
This behavior is required because some objects are immutable, but in place add still works on them.
i += 5 takes the number i is bound to, adds 5 to it, and rebinds i to the NEW result number. That is, it is exactly equivalent to i = i + 5, which has an assignment in it.
It's caused by how Python's augmented assignment operators work. After calling the appropriate special method, they assign the return value to the object at the left hand side of the operator.
If x is an instance of a
class with an __iadd__() method, x += y is equivalent to x = x.__iadd__(y). Otherwise, x.__add__(y) and y.__radd__(x) are
considered, as with the evaluation of x + y.
Therefore
my_widget.on_mouseenter += lambda source: print("on_mouseenter!")
is equivalent to
my_widget.on_mouseenter = my_widget.on_mouseenter.__iadd__(lambda source: print("on_mouseenter!"))
and you need a setter to perform assignment. It doesn't have to do anything, though, because the __iadd__ method is defined and modifies the list in-place.
On Codewars.com I encountered the following task:
Create a function add that adds numbers together when called in succession. So add(1) should return 1, add(1)(2) should return 1+2, ...
While I'm familiar with the basics of Python, I've never encountered a function that is able to be called in such succession, i.e. a function f(x) that can be called as f(x)(y)(z).... Thus far, I'm not even sure how to interpret this notation.
As a mathematician, I'd suspect that f(x)(y) is a function that assigns to every x a function g_{x} and then returns g_{x}(y) and likewise for f(x)(y)(z).
Should this interpretation be correct, Python would allow me to dynamically create functions which seems very interesting to me. I've searched the web for the past hour, but wasn't able to find a lead in the right direction. Since I don't know how this programming concept is called, however, this may not be too surprising.
How do you call this concept and where can I read more about it?
I don't know whether this is function chaining as much as it's callable chaining, but, since functions are callables I guess there's no harm done. Either way, there's two ways I can think of doing this:
Sub-classing int and defining __call__:
The first way would be with a custom int subclass that defines __call__ which returns a new instance of itself with the updated value:
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
Function add can now be defined to return a CustomInt instance, which, as a callable that returns an updated value of itself, can be called in succession:
>>> def add(v):
... return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44) # and so on..
50
In addition, as an int subclass, the returned value retains the __repr__ and __str__ behavior of ints. For more complex operations though, you should define other dunders appropriately.
As #Caridorc noted in a comment, add could also be simply written as:
add = CustomInt
Renaming the class to add instead of CustomInt also works similarly.
Define a closure, requires extra call to yield value:
The only other way I can think of involves a nested function that requires an extra empty argument call in order to return the result. I'm not using nonlocal and opt for attaching attributes to the function objects to make it portable between Pythons:
def add(v):
def _inner_adder(val=None):
"""
if val is None we return _inner_adder.v
else we increment and return ourselves
"""
if val is None:
return _inner_adder.v
_inner_adder.v += val
return _inner_adder
_inner_adder.v = v # save value
return _inner_adder
This continuously returns itself (_inner_adder) which, if a val is supplied, increments it (_inner_adder += val) and if not, returns the value as it is. Like I mentioned, it requires an extra () call in order to return the incremented value:
>>> add(1)(2)()
3
>>> add(1)(2)(3)() # and so on..
6
You can hate me, but here is a one-liner :)
add = lambda v: type("", (int,), {"__call__": lambda self, v: self.__class__(self + v)})(v)
Edit: Ok, how this works? The code is identical to answer of #Jim, but everything happens on a single line.
type can be used to construct new types: type(name, bases, dict) -> a new type. For name we provide empty string, as name is not really needed in this case. For bases (tuple) we provide an (int,), which is identical to inheriting int. dict are the class attributes, where we attach the __call__ lambda.
self.__class__(self + v) is identical to return CustomInt(self + v)
The new type is constructed and returned within the outer lambda.
If you want to define a function to be called multiple times, first you need to return a callable object each time (for example a function) otherwise you have to create your own object by defining a __call__ attribute, in order for it to be callable.
The next point is that you need to preserve all the arguments, which in this case means you might want to use Coroutines or a recursive function. But note that Coroutines are much more optimized/flexible than recursive functions, specially for such tasks.
Here is a sample function using Coroutines, that preserves the latest state of itself. Note that it can't be called multiple times since the return value is an integer which is not callable, but you might think about turning this into your expected object ;-).
def add():
current = yield
while True:
value = yield current
current = value + current
it = add()
next(it)
print(it.send(10))
print(it.send(2))
print(it.send(4))
10
12
16
Simply:
class add(int):
def __call__(self, n):
return add(self + n)
If you are willing to accept an additional () in order to retrieve the result you can use functools.partial:
from functools import partial
def add(*args, result=0):
return partial(add, result=sum(args)+result) if args else result
For example:
>>> add(1)
functools.partial(<function add at 0x7ffbcf3ff430>, result=1)
>>> add(1)(2)
functools.partial(<function add at 0x7ffbcf3ff430>, result=3)
>>> add(1)(2)()
3
This also allows specifying multiple numbers at once:
>>> add(1, 2, 3)(4, 5)(6)()
21
If you want to restrict it to a single number you can do the following:
def add(x=None, *, result=0):
return partial(add, result=x+result) if x is not None else result
If you want add(x)(y)(z) to readily return the result and be further callable then sub-classing int is the way to go.
The pythonic way to do this would be to use dynamic arguments:
def add(*args):
return sum(args)
This is not the answer you're looking for, and you may know this, but I thought I would give it anyway because if someone was wondering about doing this not out of curiosity but for work. They should probably have the "right thing to do" answer.
I've been studying magic methods in Python, and have been wondering if there's a way to outline the specific action of:
a = MyClass(*params).method()
versus:
MyClass(*params).method()
In the sense that, perhaps, I may want to return a list that has been split on the '\n' character, versus dumping the raw list into the variable a that keeps the '\n' intact.
Is there a way to ask Python if its next action is about to return a value to a variable, and change action, if that's the case? I was thinking:
class MyClass(object):
def __init__(params):
self.end = self.method(*params)
def __asgn__(self):
return self.method(*params).split('\n')
def __str__(self):
"""this is the fallback if __asgn__ is not called"""
return self.method(*params)
No. You cannot change what happens when you assign to a bare name.
You can change what happens if the assignment target on the left hand side is an attribute or item of an object. You can override a[blah] = ... with __setitem__ and a.blah = ... with __setattr__ (although you can only hook into these on a, not on the object being assigned). But you can't override or in any way influence a = ....
Note that having the right-hand side change based on what is "going to happen" would be even stranger, and very bad. That would mean that
someFunc(MyClass().method())
could be different than
a = MyClass().method()
someFunc(a)
In Python names are just labels attached to objects. Objects don't get to know what labels are attached to them, and that's a good thing. You might assign the result a computation to an intermediate variable just to make subsequent lines more readable, and you don't want that assignment to change the result of that computation.
There should be no difference between calling MyClass(*params).method() directly and assigning it to a variable. What you may be seeing here is your interpreter automatically printing return results, which is why it appears to be split while the variable value contains EOL markers.
There is no way to override default assignment to a variable. However, by using an object, you can easily provide your own hooks:
class Assigner(object):
def __init__(self, assignment_callback):
self.assignment = assignment_callback
def __setattr__(self, key, value):
if hasattr(self, 'assignment'):
value = self.assignment(value)
super(Assigner, self).__setattr__( key, value )
def uppercase(value):
# example function to perform on each attribute assignment
return value.upper()
Then in your code, rather than assigning to a variable directly you assign to attributes on your object:
>>> my = Assigner(uppercase)
>>> my.a = 'foo'
>>> print my.a
FOO
Yes.* Python allows inspecting its own stack, which can be used to peek ahead at the next instruction.
#!/usr/bin/env python3
import dis
import inspect
from itertools import dropwhile
class MyClass(object):
def method(self):
# inspect the stack to get calling line of code
frame = inspect.stack()[1].frame
# disassemble stack frame
ins = dis.get_instructions(frame.f_code)
# move to last instruction
ins = dropwhile(lambda x: x.offset < frame.f_lasti, ins)
# the last call would have been to this method/function
current_instruction = ins.__next__()
assert current_instruction.opname.startswith('CALL_')
# peek ahead at the next instruction
next_instruction = ins.__next__()
# vary behaviour depending on the next instruction
if next_instruction.opname.startswith('STORE_'):
return "returning to assignment"
elif next_instruction.opname.startswith('CALL_'):
return "returning to function/method call"
elif next_instruction.opname == 'POP_TOP':
print("return value thrown away")
return "return ignored"
elif next_instruction.opname == 'PRINT_EXPR':
return "return to interactive console"
else:
return "return to {}".format(next_instruction.opname)
This will result in the following behaviour:
a = MyClass().method()
print(a)
# returning to assignment
def someFunc(x):
return x.split()
b = someFunc(MyClass().method())
print(b)
# ['returning', 'to', 'function/method', 'call']
MyClass().method()
# return value thrown away (if called as program)
# return to interactive console (if run interactively)
* Though as the accepted answer points out, doing so is "very bad". It's also fragile, as it can be affected by bytecode optimisation. See also: Nested dictionary that acts as defaultdict when setting items but not when getting items