python init method properties usage - python

i have 2 questions:
1-Below code in the forward(self,x) method, it gets an x when the class is called. Inside of this forward(self,x) method there is a property is returning (self._forward). But there is an x variable is given to the self._forward as if it is a function. How does it work?
2- After -somehow- x value is given to the self._forward property, it chooses a policy in the policies list. I am assuming that i understood the answer of the first question and again somehow our x value that it given to self._forward goes into the here -> policies[here] and it chose a self.polcy1 or 2 or 3. How does it run the self policy1 or 2 or 3 functions without taking the value?
Sorry for my complicated explanation but a lot of things doesn't make sense here.
class SpecAugment(nn.Module):
def __init__(self,rate,policy=3,freq_mask=2,time_mask=4):
super(SpecAugment, self).__init__()
self.rate = rate
self.specaug1 = nn.Sequential(
torchaudio.transforms.FrequencyMasking(freq_mask_param=freq_mask),
torchaudio.transforms.TimeMasking(time_mask_param=time_mask)
)
self.specaug2 = nn.Sequential(
torchaudio.transforms.FrequencyMasking(freq_mask_param=freq_mask),
torchaudio.transforms.TimeMasking(time_mask_param=time_mask),
torchaudio.transforms.FrequencyMasking(freq_mask_param=freq_mask),
torchaudio.transforms.TimeMasking(time_mask_param=time_mask)
)
policies = {1:self.policy1, 2:self.policy2, 3:self.policy3}
self._forward = policies[policy]
def forward(self,x):
return self._forward(x)
#this makes specaug1
def policy1(self,x):
probability = torch.rand(1,1).item()
if self.rate > probability:
return self.specaug1(x)
return x
#this makes specaug2
def policy2(self,x):
probability = torch.rand(1,1).item()
if self.rate > probability:
return self.specaug2(x)
return x
#this makes random choice because we did torch.rand
def policy3(self,x):
probability = torch.rand(1,1).item()
if probability > 0.5:
return self.policy1(x)
return self.policy2(x)

Let's try to see what's happening here.
When you create an instance of SpecAugment, call it sa, the __init__() assigns a few properties:
sa.rate contains the rate value
sa.specaug1 and sa.specaug2 contain whatever was returned by the calls to nn.Sequential()
sa._forward contains a callable: policy1() or 2 or 3 depending on the policy value you passed in
When you call sa.forward(x), the callable from sa._forward is called with the x parameter. This in turn returns x or the result of a call to sa.specaug1 or 2, depending on the values of probabibility, sa.rate, and sa._forward.
Note that if sa.specaug1 (or sa.specaug2) isn't a callable you will get an error

Related

How to prevent the instantiation of class in python based on parameters passed in?

Lets say I have a class Vector2D that take x and y components. Because I have no interest in vectors with both components equal to zero, I want to prevent the object with both parameters passed equal to zero from being created in the first place and return None instead.
You could rename your class to RealVector2D and replace it with a new function:
def Vector2D(x, y):
if x == 0 and y == 0:
return None
return RealVector2D(x, y)
You can use a factory function to verify that your parameters are not zero, thn return an instance of Vector2D, or raise an Error:
As mentioned in the comments by #jasonsharper, returning None is not a good idea, better to return an explicit error.
class NullVectorError(ValueError):
pass
def make_non_null_vector(x: float, y: float) -> vector2D:
if x and y:
return Vector2D(x, y)
raise NullVectorError('the parameters x:{x}, and y:{y}, cannot be both equal to zero')

Python set more properties with 1 call

I have a very expensive method that returns 2 values, and it is called by class A. Since it is expensive, I made the 2 values lazy evaluated, using properties. Since I don't want to call the very_expensive_function 2 times, the first time the user wants to access one of the 2 values, I save both.
So far I wrote this:
class A:
def __init__(self):
self._attr1 = None
self._attr2 = None
#property
def attr1(self):
self.calculate_metrics()
return self._attr1
#property
def attr2(self):
self.calculate_metrics()
return self._attr2
def calculate_metrics():
if self._attr1 is None:
attr1, attr2 = very_expensive_call()
self._attr1 = attr1
self._attr2 = attr2
As you can see, the first time the user access to attr1 or attr2, I save both. Is it correct or is it possible in another way? It seems very strange to have that calculate_metrics() copy-pasted every time.
Memoization is, simply put, remembering if you have already called a function with particular arguments. If you have it simply returns the already calculated return value rather than calculating it again.
import time
def long_calculation(x, y, memo={}):
try:
result = memo[x, y] # already calculated!
except KeyError:
# make long_calculation take a long time!
time.sleep(2)
result = x * y
memo[x, y] = result
return result
The dictionary memo is able to remember calls to the function because it is evaluated when the function is first loaded: every call to long_calculation shares the same memo dictionary.
To test this try:
# Note that (2,2) (7,8) and (10,10) are repeated here:
test_values = ((2,2),(4,5),(2,2),(7,8),(2,3),(7,8),(10,11),(4,5),(10,10),(10,10))
for values in test_values:
start = time.time()
res = long_calculation(*values)
end = time.time()
elapsed = end-start
print(values,' calculated in ',elapsed, "seconds")
It should be fairly easy to insert this kind of code into your class. If you always need the attributes calculated then you can put the call in __init__.

How to take arbitrary number of parentheses from user for add function

add(5)(10)(20)
How can I to supply an arbitrary number of parentheses to add numbers?
You could create a class like so:
class add(object):
def __init__(self, value):
self.value= value
def __call__(self, value):
self.value+= value
return self
def __repr__(self):
return str(self.value)
print add(5)(10)(20)
# output: 35
It's impossible, or at least it should be if the language you're using is worth anything. You're asking for a function to return two different types, which is inviting a a disaster.
sometimes it should return a function that takes the next number to add
other times it should return the sum of the previous inputs.
What? Take a step back and ask yourself what kind of design that is. You would need need some way to notify the function that you're done giving inputs and now you want the computed value.
Think about it, the function might look like this
def add (sum):
print(sum)
return lambda x: add(sum + x)
add(1)(3)(4)(5)(10)(20)
# 1
# 4
# 8
# 13
# 23
# 43
# => None
But there's no way to let the function know to return a final value unless you change the api somehow.
You could change the api to return the computed value when the users enters a 0 or something. Great idea right? Very clever.
def add (x):
def loop(sum, x):
if x == 0:
return sum
else:
return lambda x: loop(sum + x, x)
return loop(0, x)
print(add(1)(3)(4)(5)(10)(20)(0))
# 42
Hey look, it works where #Rawling's clever code fails. All without adding a bunch of tricks to a class
print(add(5)(10)(20)(0) + add(5)(10)(20)(0))
# 70
But still, this is garbage code. No well-designed function should ever behave like this.
Or if your content with being insane, create a class like #Rawing's answer suggests.
What you could do is this:
class add(object):
def __init__(self, val):
self.val= val
def __call__(self, val=None):
if not val:
return self.val
self.val += val
return self
add(5)(10)()
>>> 15

Python: Using one argument to handle choice between a number and a string?

Basically I am writing a function that depends on a numerical input x, a number between 0 and 1. I want the default value of x to be, say, x=0.5. However, I also want to provide an option to the user that allows them to let the program select x for them using some algorithm. Is there an elegant way to handle that choice with one function argument?
I'm thinking something like this:
def foo(x=0.5):
if x == "pick for me":
return complicated_algorithm_that_picks_x()
else:
return x
def complicated_algorithm_that_picks_x():
print "Thinking hard..."
return 0.1234567
which would return:
>>> foo()
0.5
>>> foo(0.3)
0.3
>>> foo("pick for me")
Thinking hard...
0.1234567
But this looks really inelegant, since the user has to know what magic string to pass to invoke the selection algorithm. Any ideas how I can handle this more cleanly?
I was thinking having an additional Boolean argument called pick (that defaults to False), which when True will invoke the x picking function. But then users might pass both, say, x=0.3 and pass=True, in which case I have to arbitrarily ignore one of the choices. Looks clumsy again.
There are three things you might consider:
Split the one function into two.
Use a class.
Multiple default arguments.
Here there are, in no particular order:
Split one function into two
If you want to do two different things in one function and you're having trouble designing a natural interface, it might be a sign that the one function should become two:
def foo_picked_for_me():
x = pick_x()
return foo(x)
def foo(x):
# do foo
pass
I don't know how this strikes you, but it's simple, clear, and that means its often preferable.
Use a class
Default arguments are nice, but a function's interface can only get so complicated before it starts making more sense to handle option setting with a class:
class Foo:
def __init__(self):
self.x = 0.5
def pick_x_for_me(self):
self.x = pick_x()
def foo(self):
# do foo with self.x
As EOL suggests below, it's perfectly pythonic to leave x "exposed", and to allow the user to change it. You say, though, that x must be between 0 and 1, so it might make sense to do some bounds checking with the setter for x:
class Foo(object):
def __init__(self):
self._x = 0.5
#property
def x(self):
return self._x
#x.setter
def x(self, value):
if 0 <= value <= 1:
self._x = value
else:
raise ValueError("x must be between 0 and 1")
def pick_x_for_me(self):
self._x = pick_x()
def foo(self):
pass
# do foo with self._x
Multiple default arguments
The last option is analogous to what other posters have given: use two arguments, and throw an exception if the user does something contradictory. I'd consider allowing three forms of call:
# x gets its default value of 0.5
foo()
# x gets the specified value
foo(x=.42)
# x is picked for me
foo(pick_for_me=True)
Additionally, if I write:
foo(x=.42, pick_for_me=True)
I'll throw an exception. Some code that implements this follows:
def foo(x=None, pick_for_me=None):
if x is None and pick_for_me is None:
x = 0.5
elif pick_for_me and x:
raise RuntimeError("You can't set both!")
elif pick_for_me:
x = picking_algorithm()
# else x was set, so leave it be
This is kind of complicated, and I'm not so sure I like the API. Just make sure you document the behavior well enough so that the user knows how to use the thing.
Try this:
def foo(x=0.5, use_complex_algo=False):
if use_complex_algo == False:
return x
else:
return complicated_algorithm_that_picks_x()
#ouput
print foo() # returns: 0.5
print foo(0.3) # returns: 0.3
print foo(use_complex_algo=True) # returns: 0.1234567
I would probably define a constant in the module that indicates to generate a random value. For example:
# foo.py
import random
RANDOM = 'random'
def foo(x=0.5):
if x == RANDOM:
x = random.random()
if x < 0 or x > 1:
raise ValueError('x must be between 0 and 1')
return x
Then, to use it is pretty straightforward:
>>> import foo
>>> foo.foo(0.1)
0.1
>>> foo.foo()
0.5
>>> foo.foo(foo.RANDOM)
0.4388309758578337
>>> foo.foo(foo.RANDOM)
0.5351558099071574
>>> foo.foo(7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "foo.py", line 9, in foo
raise ValueError('x must be between 0 and 1')
ValueError: x must be between 0 and 1
I think this code would do what all you want!
import random
def foo(x=0.5):
if x=="pick for me":
return random.random()
else:
return x
print foo()
print foo("pick for me")
print foo(0.3)
Assuming the parameter type passed is float (can also be checked), you could define that any input < 0 or > 1 means "pick for me"...
It also kind of validates that the passed parameter is within range, and if not generates a proper value.
But this does not really answer the question about choosing between a number & a string ;-) (type() could help for this)
def foo(x=0.5):
if 0 <= x <= 1:
return x
else:
return complicated_algorithm_that_picks_x()

Is it possible to make Python functions behave like instances?

I understand that functions can have attributes. So I can do the following:
def myfunc():
myfunc.attribute += 1
print(myfunc.attribute)
myfunc.attribute = 1
Is it possible by any means to make such a function behave as if it were an instance? For example, I'd like to be able to do something like this:
x = clever_wrapper(myfunc)
y = clever_wrapper(myfunc)
x.attribute = 5
y.attribute = 9
x() # I want this to print 6 (from the 5 plus increment)
y() # I want this to print 10 (from the 9 plus increment)
As it stands, there is only one "instance" of the function, so attribute only exists once. Modifying it by either x or y changes the same value. I'd like each of them to have their own attribute. Is that possible to do at all? If so, can you provide a simple, functional example?
It is important that I be able to access attribute from inside of the function but have the value of attribute be different depending on which "instance" of the function is called. Essentially, I'd like to use attribute as if it were another parameter to the function (so that it could change the behavior of the function) but not pass it in. (Suppose that the signature of the function were fixed so that I cannot change the parameter list.) But I need to be able to set the different values for attribute and then call the functions in sequence. I hope that makes sense.
The main answers seem to be saying to do something like this:
class wrapper(object):
def __init__(self, target):
self.target = target
def __call__(self, *args, **kwargs):
return self.target(*args, **kwargs)
def test(a):
return a + test.attribute
x = wrapper(test)
y = wrapper(test)
x.attribute = 2
y.attribute = 3
print(x.attribute)
print(y.attribute)
print(x(3))
print(y(7))
But that doesn't work. Maybe I've done it incorrectly, but it says that test does not have attribute. (I'm assuming that it's because wrapper actually has the attribute.)
The reason I need this is because I have a library that expects a function with a particular signature. It's possible to put those functions into a pipeline of sorts so that they're called in order. I'd like to pass it multiple versions of the same function but change their behavior based on an attribute's value. So I'd like to be able to add x and y to the pipeline, as opposed to having to implement a test1 function and a test2 function that both do almost exactly the same thing (except for the value of the attribute).
You can make a class with a __call__ method which would achieve a similar thing.
Edit for clarity: Instead of making myfunc a function, make it a callable class. It walks like a function and it quacks like a function, but it can have members like a class.
A nicer way:
def funfactory( attribute ):
def func( *args, **kwargs ):
# stuff
print( attribute )
# more stuff
return func
x = funfactory( 1 )
y = funfactory( 2 )
x( ) # 1
y( ) # 2
This works because the functions are closures, so they will grab all local variables in their scope; this causes a copy of attribute to be passed around with the function.
class Callable(object):
def __init__(self, x):
self.x = x
def __call__(self):
self.x += 1
print self.x
>> c1 = Callable(5)
>> c2 = Callable(20)
>> c1()
6
>> c1()
7
>> c2()
21
>> c2()
22
A generator might be an alternate solution here:
def incgen(init):
while True:
init += 1
print init
yield
x = incgen(5)
y = incgen(9)
x.next() # prints 6
y.next() # prints 10
y.next() # prints 11
x.next() # prints 7
You can't dig back in to the generator and manipulate the data though.
#!/usr/bin/env python
# encoding: utf-8
class Callable(object):
attribute = 0
def __call__(self, *args, **kwargs):
return self.attribute
def main():
c = Callable()
c.attribute += 1
print c()
if __name__ == '__main__':
main()

Categories

Resources