I know its dumb question but i am trying to grasp the concepts of OOP in Python. Suppose i want to write the program for factorial in Procedural form, i would do something like this
def factorial(n):
num = 1
while n >= 1:
num = num * n
n = n - 1
return num
f = factorial(3)
print f # 6
Now i want to rewrite the same factorial program in OO way. i am not getting how to write this same function using objects and classes.
class Factorial():
def fact(n):
num = 1
while n >= 1:
num = num * n
n = n - 1
return num
f = Factorial()
a = f.fact(3)
print a # TypeError: fact() takes exactly 1 argument (2 given)
I know this can be done more precisely in Functional way by using lambdas and other things, but i am learning the concepts of OOP. What i am doing wrong ?
When you are calling an instance method, by default the current object is passed as the first parameter to the function. In your case,
def fact(n):
when you call it like this
a = f.fact(3)
it will be actually treated like this
a = fact(f, 3)
The reason why the current object is passed is, to let the instance method make changes to the object. (Remember Python doesn't have any other keyword like this, like in some other languages).
But your function's signature doesn't match this (it expects only one parameter). That's why it is throwing
# TypeError: fact() takes exactly 1 argument (2 given)
To fix this, you have to change the signature to something like this
def fact(self, n):
Now, the self parameter will receive the current object being passed.
You forgot the self parameter:
class Factorial():
def fact(self,n): #Forgot the self parameter huh?
num = 1
while n >= 1:
num = num * n
n = n - 1
return num
I recommend you read these too:
explaining the self variable to a beginner
Python 'self' explained
Dive into Python - defining Classes
I would also recommend these article for reading:
An Introduction to Object-Oriented Concepts in Python, Part 1
Unfortunately I cannot put more that 2 links But I'm sure you'll find other 4 parts of these.
Related
I am new to Python and I need to write function sum with similar syntax:
print(sum())
print(sum(1)(2)(3))
print(sum(1)(2)(3)(-4)(-5))
The output is:
0
6
-3
I tried to write decorator like this:
def sum(a=0):
res = a
def helper(b=0):
nonlocal res
res += b
return res
return helper
But it helps only with fixed quantity of (). So this code works only for: sum(1)(2)->3 and doesn't for sum()-><function sum.<locals>.helper at 0x7fca6de44160> or sum(1)()(3) -> TypeError: 'int' object is not callable
I think there should be a decorator with recursion, but i don't know how to realize it
That syntax choice looks very odd to me - should the result of sum(foo) be a number or a function? The built-in sum just takes an iterable and returns a number, which feels much less surprising.
However, assuming that you are certain you indeed want to create something that looks like an integer, walks like an integer, swims like an integer but is also callable, the language does let you create it:
class sum(int):
def __call__(self, x=0):
return sum(self + x)
The output is as you specified:
print(sum())
print(sum(1)(2)(3))
print(sum(1)(2)(3)(-4)(-5))
0
6
-3
Finaly, I found my way of solving this task (using only functions):
def sum(x=None):
value = 0
def helper(y=None):
nonlocal value
if y is None:
return value
value += y
return helper
return helper(x)
Well honestly no easy way for me to lamens the title of this question, basically is there a way to modify a return value for a function while also returning it in the same line.
Example - custom implementation of an iterable class
I’d like to replace this:
def __next__(self):
if self.count <= 0:
raise StopIteration
r = self.count
self.count -= 1
return r
With this:
def __next__(self):
if self.count <= 0:
raise StopIteration
return self.count -= 1
Honestly, I know this may seem frivolous (which it may be) but I’m only this because I’m a fan of one-liners and this boils down to making even a process as simple as this more logically readable; plus, depending on the implementation, it would nullify having to hold the value r in memory (I know I know, removing the need for r has no significant gain but hey I’m only asking if this is possible).
I know I’ve only given one example but this happens to be the only case I can think of that something like this Would be needed. Python is a wonderful language full of many special things like += being a “wrapper” of __iadd__ my thing is am I missing something? Or is this possible... and why must it be used as a single line and not in conjunction with a return statement as it doesn’t return its altered value?
It's because -= modifies the variable, and do any thing to that, (like now you returned that) will raise errors.
Demo:
>>> a=3
>>> a+(a+=1)
SyntaxError: invalid syntax
>>> # also to show that it does modify the variable:
>>> a=3
>>> a+=1
>>> a
4
>>>
Update:
You do a two-liner:
def f(a):
if a<=0:raise StopIteration
a-=1;return a
return foobar -= 1
or
>>> a = 3
>>> b = (a += 1)
File "<stdin>", line 1
b = (a += 1)
^
SyntaxError: invalid syntax
is not possible in Python.
Although the first solution needs to store one more variable for this timestep (or do one operation more), to cite the Python Zen: Readability counts.
I am new to learn python these days. While reading a book, I found a line of code that I can't understand.
Please see line 46 under print_progression() method, print(' '.join(str(next(self)) for j in range(n))).
class Progression:
'''Iterator producing a generic progression.
Default iterator produces the whole number, 0, 1, 2, ...
'''
def __init__(self, start = 0):
'''
Initialize current to the first value of the progression.
'''
self._current = start
def _advance(self):
'''
Update self.current to a new value.
This should be overriden by a subclass to customize progression.
By convension, if current is set to None, this designates the
end of a finite progression.
'''
self._current += 1
def __next__(self):
'''
Return the next element, or else raise StopIteration error.
'''
# Our convention to end a progression
if self._current is None:
raise StopIteration()
else:
# record current value to return
answer = self._current
# advance to prepare for next time
self._advance()
# return the answer
return answer
def __iter__(self):
'''
By convention, an iterator must return itself as an iterator.
'''
return self
def print_progression(self, n):
'''
Print next n values of the progression.
'''
print(' '.join(str(next(self)) for j in range(n)))
class ArithmeticProgression(Progression): # inherit from Progression
pass
if __name__ == '__main__':
print('Default progression:')
Progression().print_progression(10)
'''Output is
Default progression:
0 1 2 3 4 5 6 7 8 9 10'''
I have no idea how next(self) and j works.
I think it should be str(Progression.next()). (solved)
I cannot find j anywhere. What is j for? Why not using while loop such as while Progression.next() <= range(n)?
For my final thought, it should be
print(' '.join(str(next(self)) while next(self) <= range(n)))
Save this newbie.
Thanks in advance!
I think #csevier added a reasonable discussion about your first question, but I'm not sure the second question is answered as clearly for you based on your comments so I'm going to try a different angle.
Let's say you did:
for x in range(10):
print(x)
That's reasonably understandable - you created a list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] and you printed each of the values in that list in-turn. Now let's say that we wanted to just print "hello" 10 times; well we could modify our existing code very simply:
for x in range(10):
print(x)
print('hello')
Umm, but now the x is messing up our output. There isn't a:
do this 10 times:
print('hello')
syntax. We could use a while loop but that means defining an extra counter:
loop_count = 0
while loop_count < 10:
print('hello')
loop_count += 1
That's baggage. So, the better way would be just to use for x in range(10): and just not bother doing print(x); the value is there to make our loop work, not because it's actually useful in any other way. This is the same for j (though I've used x in my examples because I think you're more likely to encounter it in tutorials, but you could use almost any name you want). Also, while loops are generally used for loops that can run indefinitely, not for iterating over an object with fixed size: see here.
Welcome to the python community! This is a great question. In python, as in other languages, there are many ways to do things. But when you follow a convention that the python community does, that is often referred to as a "pythonic" solution. The method print_progression is a common pythonic solution to iteration of a user defined data structure. In the case above, lets explain first how the code works and then why we would do it that way.
Your print_progression method takes advantage of the fact that your Progression class implements the iteration protocol by implementing the next and iter dunder/magic methods. Because those are implemented you can iterate your class instance both internally as next(self) has done, and externally next(Progression()) which is the exactly what you were getting at with you number 1. Because this protocol is implemented already, this class can by used in any builtin iterator and generator context for any client! Thats a polymorphic solution. Its just used internally as well because you don't need to do it in 2 different ways.
Now for the unused J variable. They are just using that so they can use the for loop. Just using range(n) would just return an itterable but not iterate over it. I dont quite agree with the authors use of the variable named J, its often more common to denote an unused variable that is just used because it needs to be as a single underscore. I like this a little better:
print(' '.join(str(next(self)) for _ in range(n)))
I am reading Hackers and Painters and am confused by a problem mentioned by the author to illustrate the power of different programming languages.
The problem is:
We want to write a function that generates accumulators—a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That’s incremented by, not plus. An accumulator has to accumulate.)
The author mentions several solutions with different programming languages. For example, Common Lisp:
(defun foo (n)
(lambda (i) (incf n i)))
and JavaScript:
function foo(n) { return function (i) { return n += i } }
However, when it comes to Python, the following codes do not work:
def foo(n):
s = n
def bar(i):
s += i
return s
return bar
f = foo(0)
f(1) # UnboundLocalError: local variable 's' referenced before assignment
A simple modification will make it work:
def foo(n):
s = [n]
def bar(i):
s[0] += i
return s[0]
return bar
I am new to Python. Why doesn the first solution not work while the second one does? The author mentions lexical variables but I still don't get it.
s += i is just sugar for s = s + i.*
This means you assign a new value to the variable s (instead of mutating it in place). When you assign to a variable, Python assumes it is local to the function. However, before assigning it needs to evaluate s + i, but s is local and still unassigned -> Error.
In the second case s[0] += i you never assign to s directly, but only ever access an item from s. So Python can clearly see that it is not a local variable and goes looking for it in the outer scope.
Finally, a nicer alternative (in Python 3) is to explicitly tell it that s is not a local variable:
def foo(n):
s = n
def bar(i):
nonlocal s
s += i
return s
return bar
(There is actually no need for s - you could simply use n instead inside bar.)
*The situation is slightly more complex, but the important issue is that computation and assignment are performed in two separate steps.
An infinite generator is one implementation. You can call __next__ on a generator instance to extract successive results iteratively.
def incrementer(n, i):
while True:
n += i
yield n
g = incrementer(2, 5)
print(g.__next__()) # 7
print(g.__next__()) # 12
print(g.__next__()) # 17
If you need a flexible incrementer, one possibility is an object-oriented approach:
class Inc(object):
def __init__(self, n=0):
self.n = n
def incrementer(self, i):
self.n += i
return self.n
g = Inc(2)
g.incrementer(5) # 7
g.incrementer(3) # 10
g.incrementer(7) # 17
In Python if we use a variable and pass it to a function then it will be Call by Value whatever changes you make to the variable it will not be reflected to the original variable.
But when you use a list instead of a variable then the changes that you make to the list in the functions are reflected in the original List outside the function so this is called call by reference.
And this is the reason for the second option does work and the first option doesn't.
I'm trying to write an implementation of a genetic algorithm in python. It says there I am calling it with two arguments when only one is allowed, but I'm sure I'm not.
Here is the relevant code:
class GA:
def __init__(self, best, pops=100, mchance=.07, ps=-1):
import random as r
self.pop = [[] for _ in range(pops)]
if ps == -1:
ps = len(best)
for x in range(len(self.pop)): #Creates array of random characters
for a in range(ps):
self.pop[x].append(str(unichr(r.randint(65,122))))
def mutate(array):
if r.random() <= mchance:
if r.randint(0,1) == 0:
self.pop[r.randint(0, pops)][r.randint(0, ps)] +=1
else:
self.pop[r.randint(0, pops)][r.randint(0, ps)] -=1
This is the code when I initialize and call from the class:
a = GA("Hello",10,5)
a.mutate(a.pop)
which returns the following error from IDLE:
TypeError: mutate() takes exactly 1 argument (2 given)
How can I fix this?
Methods of a class are automatically passed the instance of the class as their first argument (it's named self by convention):
def mutate(self, array):