I have a program which goes as follows
data = bytes()
...
new_data = bytes()
...
data += new_data
print(data)
and so I have mocked bytes accordingly along with the __iadd__ call as follows:
#unittest.mock.patch('file_name.bytes')
def test(self, mock_bytes):
mock_bytes.__iadd__.return_value = mock_bytes
...
From my understanding, a MagicMock of bytes() should be returned, but instead I get a MagicMock of bytes().__iadd__().
I'd appreciate any help on the matter :)
P.S. have also tried variations like mock_bytes(), mock_bytes().__iadd__(), or any other variation.
In short, the mock works as expected. To override data += new_data you should have this syntax: mock_bytes.return_value.__iadd__.return_value = "the value which is printed".
A note about mock syntax: you can often replace .return_value with (), so mock_bytes.return_value.__iadd__.return_value = "the value which is printed" is equivalent to mock_bytes().__iadd__.return_value = "the value which is printed"
Now, as to why you need the () / .return_value in the first place:
Mocks are tied to the implementation - they mimic the functions called. So if you want to change the value of data variable in this line: data = bytes() you are changing the return value of the function bytes. You were right to identify that iadd is called, and once more, you want to change the return value.
Then you have concatenation/chaining of calls: you are calling bytes, then apply iadd on the returned object. So you have this syntax: mock_bytes.return_value.__iadd__.return_value = "the value which is printed"
Related
Why do the following lines give me the same result?
str.upper('hello')
and
'hello'.upper()
I tried to do the same with list.append but got a TypeError.
list.append([1])
Is the str type in Python overloaded? How can this be achieved by writing a class/function? I would appreciate an example.
list.append takes two arguments - the list to modify and the element to append. So you need to do it like this:
ls = [1]
list.append(ls, 2)
which is equivalent to the much more popular:
ls.append(2)
str.upper and list.append are both functions.
str.upper takes one argument.
>>> str.upper('test')
'TEST'
list.append takes two arguments.
>>> my_list = []
>>> list.append(my_list, 1)
>>> my_list
[1]
str.upper and list.append (like other functions) are also non-data-descriptors with a __get__ method which in this context has two implications:
When you access the function through the class via the dot notation (str.upper, list.append) the function's __get__ method (i.e. string.upper.__get__ and list.append.__get__) is called but it returns just the function itself.
When you access the function through an instance (my_string.upper, my_list.append) the function's __get__ method is called and it will return a new callable acting like the original function, but with whatever was "in front of the dot" automatically passed as the first argument. .
That's why you need to pass 1 - 1 = 0 arguments when calling my_string.upper() and 2 - 1 = 1 argument when calling my_list.append(1).
>>> 'my_string'.upper()
'MY_STRING'
>>>
>>> my_list = []
>>> my_list.append(1)
>>> my_list
[1]
You could even get these modified callables (methods) by explicitly calling __get__ and passing the argument to be bound (what has been before the dot) as its argument.
>>> my_string = 'my_string'
>>> upper_maker = str.upper.__get__(my_string)
>>> upper_maker()
'MY_STRING'
>>>
>>> my_list = []
>>> appender = list.append.__get__(my_list)
>>> appender(1)
>>> my_list
[1]
Finally, here's a short example demonstrating how descriptor instances can detect whether they are being accessed via their owner-class or via an instance.
class Descriptor:
def __get__(self, instance, owner_class):
if instance is None:
print('accessed through class')
# list.append.__get__ would return list.append here
else:
print('accessed through instance')
# list.append.__get__ would build a new callable here
# that takes one argument x and that internally calls
# list.append(instance, x)
class Class:
attribute = Descriptor()
Class.attribute # prints 'accessed through class'
instance = Class()
instance.attribute # prints 'accessed through instance'
Quoting Dave Kirbys answer from Relationship between string module and str:
There is some overlap between the string module and the str type,
mainly for historical reasons. In early versions of Python str objects
did not have methods, so all string manipulation was done with
functions from the string module. When methods were added to the str
type (in Python 1.5?) the functions were left in the string module for
compatibility, but now just forward to the equivalent str method.
However the string module also contains constants and functions that
are not methods on str, such as formatting, character translation etc.
There is nothing at all magical going on with str (except that we have a nice syntactic shortcut to creating one using ""). You can write a class that behaves like str and list to see more clearly what is happening here.
class MyClass():
def __init__(self, arg):
self.val=str(arg)
def do_thing(self):
self.val = "asdf"
def do_thing_with_arg(self, arg):
self.val = "asdf " + str(arg)
def __repr__(self):
return self.val
my_thing = MyClass("qwerty")
# this is like 'hello'.upper()
my_thing.do_thing()
print(my_thing)
# it prints 'asdf'
my_thing = MyClass("qwerty")
# this is like str.upper('hello')
MyClass.do_thing(my_thing)
print(my_thing)
# it prints 'asdf'
my_thing = MyClass("qwerty")
# this is like my_list.append('qwerty')
my_thing.do_thing_with_arg('zxcv')
print(my_thing)
# it prints 'asdf zxcv'
my_thing = MyClass("qwerty")
# this is like list.append(my_list, 'qwerty')
MyClass.do_thing_with_arg(my_thing, 'zxcv')
print(my_thing)
# it prints 'asdf zxcv'
The short version is, you're invoking what looks like an "instance method" on a class, but you are supplying the instance ('self') yourself as the first argument to the function call.
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 am trying to make a decrypter that decrypts code from the encrypter I made. I am getting this type error when I run the code though
getcrypt = ''.join(map(Decrypt.get,split_up_into_sixteen_chars(x_str)))
TypeError: split_up_into_sixteen_cjars() takes 0 positional arguments but 1 was given
I'm fairly new to programming and not sure whats causing this.
heres my code
Decrypt = {'1s25FF5ML10IF7aC' : 'A', 1s2afF5ML10I7ac' : 'a'} #I obviously have more than this but I'm trying to make it as simplified as possible
def split_up_into_sixteen_chars():
while len(x_str)>0:
v = x_str[:16]
print(v)
x_str = (input())
getcrypt = ''.join(map(Decrypt.get,split_up_into_sixteen_chars(x_str)))
print(getcrypt)
You have defined a function that takes no parameters:
def split_up_into_sixteen_chars():
yet you are passing it one:
split_up_into_sixteen_chars(x_str)
You need to tell Python that the function takes one parameter here, and name it:
def split_up_into_sixteen_chars(x_str):
The name used does not have to match the name that you pass in for the function call, but it does have to match what you use inside the function. The following function would also work; all I did was rename the parameter:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
print(v)
This works because the parameter some_string becomes a local name, local to the function. It only exists inside of the function, and is gone again once the function completes.
Note that your function creates an infinite loop; the length of some_string will either always be 0, or always be longer than 0. The length does not change in the body of the loop.
The following would work better:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
print(v)
some_string = some_string[16:]
because then we replace some_string with a shorter version of itself each time.
Your next problem is that the function doesn't return anything; Python then takes a default return value of None. Printing is something else entirely, print() writes the data to your console or IDE, but the caller of the function does not get to read that information.
In this case, you really want a generator function, and use yield. Generator functions return information in chunks; you can ask a generator for the next chunk one by one, and that is exactly what map() would do. Change the function to:
def split_up_into_sixteen_chars(some_string):
while len(some_string) > 0:
v = some_string[:16]
yield v
some_string = some_string[16:]
or even:
def split_up_into_sixteen_chars(some_string):
while some_string:
yield some_string[:16]
some_string = some_string[16:]
because an empty string is 'false-y' when it comes to boolean tests as used by while and if.
As your map(Decrypt.get, ...) stands, if split_up_into_sixteen_chars() yields anything that is not present as a key in Dycrypt, a None is produced (the default value for dict.get() if the key is not there), and ''.join() won't like that. The latter method can only handle strings.
One option would be to return a string default instead:
''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
Now '', the empty string, is returned for chunks that are not present in Decrypt. This makes the whole script work for whatever string input you have:
>>> x_str='Hello world!'
>>> ''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
''
>>> x_str = '1s25FF5ML10IF7aC'
>>> ''.join(map(lambda chunk: Decrypt.get(chunk, ''), split_up_into_sixteen_chars(x_str)))
'A'
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
I have a function that has several outputs, all of which "native", i.e. integers and strings. For example, let's say I have a function that analyzes a string, and finds both the number of words and the average length of a word.
In C/C++ I would use # to pass 2 parameters to the function. In Python I'm not sure what's the right solution, because integers and strings are not passed by reference but by value (at least this is what I understand from trial-and-error), so the following code won't work:
def analyze(string, number_of_words, average_length):
... do some analysis ...
number_of_words = ...
average_length = ...
If i do the above, the values outside the scope of the function don't change. What I currently do is use a dictionary like so:
def analyze(string, result):
... do some analysis ...
result['number_of_words'] = ...
result['average_length'] = ...
And I use the function like this:
s = "hello goodbye"
result = {}
analyze(s, result)
However, that does not feel right. What's the correct Pythonian way to achieve this? Please note I'm referring only to cases where the function returns 2-3 results, not tens of results. Also, I'm a complete newbie to Python, so I know I may be missing something trivial here...
Thanks
python has a return statement, which allows you to do the follwing:
def func(input):
# do calculation on input
return result
s = "hello goodbye"
res = func(s) # res now a result dictionary
but you don't need to have result at all, you can return a few values like so:
def func(input):
# do work
return length, something_else # one might be an integer another string, etc.
s = "hello goodbye"
length, something = func(s)
If you return the variables in your function like this:
def analyze(s, num_words, avg_length):
# do something
return s, num_words, avg_length
Then you can call it like this to update the parameters that were passed:
s, num_words, avg_length = analyze(s, num_words, avg_length)
But, for your example function, this would be better:
def analyze(s):
# do something
return num_words, avg_length
In python you don't modify parameters in the C/C++ way (passing them by reference or through a pointer and doing modifications in situ).There are some reasons such as that the string objects are inmutable in python. The right thing to do is to return the modified parameters in a tuple (as SilentGhost suggested) and rebind the variables to the new values.
If you need to use method arguments in both directions, you can encapsulate the arguments to the class and pass object to the method and let the method use its properties.