Conversation started Nov 1, 2019 at 5:49.
Nov 1, 2019 05:49
@JohnRennie import math
def area_rect(a,b):
	return a*b
def triangle (a,b,c):
	s=(a+b+c)/2
	area=math.sqrt(s*(s-a)*(s-b)*(s-c))
	return area

PI=3.14
def area_circle(r):
	return Pi*r*r
the filename is 184.py
so i typed from module 184.py import PI
print(PI)
but when i run it,it shows error
Give me a moment and I'll look at some old code I've written that does imports ...
Try print(184.PI)
Oh wait:
from 184 import PI
Not from module 184 import PI
okay.let me try again
@JohnRennie not working
can u pose the code
post
OK, in the file 184.py I have:
import math

def area_rect(a,b):
	return a*b

def triangle (a,b,c):
	s=(a+b+c)/2
	area=math.sqrt(s*(s-a)*(s-b)*(s-c))
	return area

PI=3.14

def area_circle(r):
	return Pi*r*r
Now I do:
Ah, I don't think you can have a module name that is a number ...
hmm ok
can it be mix of alphabet and numbers?
>>> from a184 import PI
>>> PI
3.14
Nov 1, 2019 06:00
aha ok
I renamed the file to a184.py and now it works.
let me try
@JohnRennie How did u rename
when i change name in save as option
it still retains 184.py
Are you working in Windows or Linux
windows
Open a command prompt, change to the durectory where the file is and use the command:
rename 184.py a184.py
(Close the editor first)
Nov 1, 2019 06:06
ah it imported
@JohnRennie Hi
import a186

print('area:',a186.area_rect(20,10))
print('area:',a186.area_triangle(3,4,5))
print('area:',a186.area.circle(7))
why is this not working
@JohnRennie nvm it's working...
@Aladdin OK :-)
Nov 1, 2019 06:24
@JohnRennie how does module work
can u explain ...i am not getting it
is module object
In effect when you import a module it just runs the Python in that module.
So when you import a184.py it runs the code in the file and that defines the functions and the constant PI.
okay
so essentially its an object that contains the codes
It's just a file with Python code in. Though the Python interpreter may preprocess the file onthe first import to speed up subsequent imports.
If you look in the directory where a184.py is you'll probably find a file called a184.pyc.
This is the preprocessed version of a184.py.
@JohnRennie HOW do you find directory
i can't find it
Have you got a command prompt open?
Nov 1, 2019 06:34
ye
Doesn't it show the directory name to the left of where the cursor is flashing?
it shows some name
is that drectory
So for me it's D:\rhs\Python
what is D
Local disk D
Ohk
You probably only have a C: disk. My PC has two disks.
Ah, it looks as if Python 3.7 creates the file in a subdirectory called __pycache__
Nov 1, 2019 06:39
ok ifound pyc file
it's in a folder like u said pycache
When you first import a .py file Python processes it to create a .pyc file. Then on subsequent imports Python will import the .pyc file as that's quicker.
If you then change the .py file Python will spot the change and reprocess it to create a new .pyc file.
what happens in the pyc file
Try opening the .pyc file in Notepad (or whatever editor you want). You'll find it's a binary file not a text file.
It's your original code processed by Python to make it quicker to import.
But I say this just out of interest. You don't need to know this to use Python.
ok let me try
how do i open in notepad.
Right click the .pyc file and choose Open with ...
Nov 1, 2019 06:44
ok
okay i see it
I get stuff like this.
same
The .pyc file is only meant to be read by Python, not by humans!
so python runs the pyc file and imports everything from it
Yes.
When you import math or any other of the standard modules you are basically importing a .pyc file, and that .pyc file was created from Python code.
Nov 1, 2019 07:29
@JohnRennie hi
@Aladdin hi
1.def f1():
	x=10
	print(x)
	def f2():
		nonlocal x
		x=x+2
		print(x)
	f2()
f1()
how does this not show error
I need to work now I'm afraid. I'll be about half an hour.
ohkay
ping me when back
from what i remeber x=10 is limited only to scope f1 and f2 can only read it but can't change it
Nov 1, 2019 08:03
@Aladdin The command nonlocal x inside f2() specifies that the variable x is the same variable as defined in f1(). It's kind of like global, except that it only works inside the parent function i.e. inside f1().
so now the inner function can read and change the variable
I have anther doubt
When you call a function with a parameter, a new reference is created that refers to the object passed in. This is separate from the reference that was used in the function call, so there's no way to update that reference and make it refer to a new object. In your example:

def __init__(self):
    self.variable = 'Original'
    self.Change(self.variable)

def Change(self, var):
    var = 'Changed'
self.variable is a reference to the string object 'Original'. When you call Change you create a second reference var to the object. Inside the function you reassign the reference var to a differen
can u exlain what this means..i am afraid i am still having doubts with these
Nov 1, 2019 08:11
Where did that come from?
it's just something i found on stack overflow
It's basically just saying that:
x = 1

def f1(y):
	y = 2

print(x)
f1(x)
print(x)
prints:
D:\rhs\Python>python test.py
1
1
i.e. the function f1(y) only has read access to the parameter.
@JohnRennie unction can't change x
python is a bit weird
Yes. When f1() does y=2 it actually creates a new variable unrelated to the original variable.
Try:
x = 1

def f1(y):
    print(id(y))
    y = 2
    print(id(y))

print(id(x))
f1(x)
And you'll find the id changes when you execute y = 2
x = 1
print(id(x))

def f1(y):
    print(id(y))
    y = 2
    print(id(y))

f1(x)
yep
the reference x is passed inside the function
it points to 1
then y points to 1
so x and y point to same bject
then u change y
so id changes
because now y points to diferent object
that's what my analysis is
@JohnRennie Do you know about closures
Nov 1, 2019 08:31
@Aladdin yes.
@Aladdin closures?
What about them?
@JohnRennie Hi.I will be back in 5 minutes
OK ...
@JohnRennie back
def foo():
	print("hai")
	def foo1():
		print("hello")
	return foo1
a=foo()
a()

output:
hello
can you explain
Suppose you tried:
def foo():
	print("hai")
	def foo1():
		print("hello")
	return foo1

foo1()
What do you think will happen?
hai
return foo1 ...idk
wait it shuld show error
syntax rror
we can't access foo1()
Nov 1, 2019 08:46
D:\rhs\Python>python test.py
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    foo1()
NameError: name 'foo1' is not defined
Yes.
But when call foo() the return value is a function. Specifically it is the function f001.
i didn't get
When the function foo executes the line return foo1 this causes Python to create an object, put the function foo1 into that object and then return a reference to that object.
oksy
So when you do a = foo() the variable a is now a reference to an object containing the functon foo1.
so foo1 will be stored as an object in memory locatio of foo()?
Nov 1, 2019 08:50
foo1 will be stored as an object in memory so that a can refer to it.
The bit of memory it's stored in isn't related to where foo() is stored in memory.
When the function foo executes the line return foo1 this causes Python to create an object, put the function foo1 into that object and then return a reference to that object.
how do we know the reference?
When you execute a = foo() the reference returned by foo() gets stored in a.
Try this:
def foo():
	print("hai")
	def foo1():
		print("hello")

	print(id(foo1))
	return foo1

a = foo()
print(id(a))
How do you think id(foo1) and id(a) will compare?
@JohnRennie foo1 becomes the object?
i can't go past this ...
Basically a becomes foo1
no let's take a step back
def foo():
	print("hai")
	def foo1():
		print("hello")

	print(id(foo1))
	return foo1
Nov 1, 2019 08:57
So when you execute a() it's like executing foo1() even though in theory foo1 should be inaccessible bacuse it's hidden inside foo().
@JohnRennie what happens during return foo1?
foo1 gets stored in an object?
Let's take a step back ...
and we get the refrence of that object
@JohnRennie ok
A computer has memory. That memory is like a big array of bytes starting at zero and going up to 4GB or however much memory your computer has.
Suppose we have a command x = 1
Nov 1, 2019 09:01
Python stores the value 1 in some bit of memory. Suppose it stores it in byte number 1234. That is, the memory is just an array of bytes starting at 0 and 1234 is the offset in the memory where Python stores the data 1.
The reference to this memory is just its offset i.e. 1234.
So if we represent the memory as an array memory[] then memory[1234] = 1.
The value of the variable is the data 1 and the reference to it is its offset 1234.
Does this make sense so far?
That is, the memory is just an array of bytes starting at 0 and 1234 is the offset in the memory where Python stores the data 1.
didn't understand this line
How much memory does your computer have? 4GB? 8GB?
@JohnRennie 8
Nov 1, 2019 09:07
Ok, so that means it has 8589934592 bytes of memory.
And when the computer wants to store a number, e.g. 1, it has to choose which one of those bytes to put the number in.
The computer numbers the bytes starting at zero. So byte zero is the first byte, byte one is the second byte and so on.
Nov 1, 2019 09:09
When it stores the data 1 in one of the bytes that byte will have some number.
What number the computer chooses depends on lots of things that don't concern us. All I'm saying is that the data 1 will be stored somewhere, and that byte where it's stored will have a number.
got it
And I saying suppose that number happens to be 1234.
In computerspeak the address of the byte is 1234 and the contents of the byte are the data we stored there i.e. 1.
Nov 1, 2019 09:13
When we talk about references we basically mean the number of the byte where the data is stored. So when we do x = 1 the variable x will have the value 1 and id(x) = 1234.
That is, the name x is a reference set to 1234, and when we want the value of x we look in memory byte 1234 and pull out the data stored there.
aha okay
Now back to that code ...
when we do def foo1 the code for the function foo1 gets stored in some bit of memory and foo1 is set to the address of that memory.
So when we call foo1() what Python does is look at the address stored in the reference foo1 - suppose this is 4321.
Nov 1, 2019 09:16
Then it goes to byte 4321 and gets the code stored there and executes it.
So when we do return foo1 we are returning the address 4321.
And when we do a = foo() then a gets set to 4321.
oh
so a is a memory location
And when we execute a() Python looks at the address stored in a (i.e. 4321) gets the code stored at that address and executes it.
And of course that's the very same code that got stored at address 4321 when we did def foo1().
@JohnRennie Aha.Okay
In a way, if you'd started with C this would be easier because in C the difference between an address and a value is very clear. Python tries to hide this from you to make life simpler, but then when you do need to look more closely you find yourself wondering what is going on.
@JohnRennie It's the difference between foo1() and foo1
You can try this at the console. Give me a moment to try it ...
>>> def foo1():
... print("This function prints foo1")
...
>>> foo1
<function foo1 at 0x0000023CC40370D8>
>>> foo1()
This function prints foo1
There. You can try this for yourself.
First I define the function foo1.
Now if I just type foo1 this is an object called foo1 containing a function, so Pyhton shows <function foo1 at 0x0000023CC40370D8> which is an internal representation of the function.
i think i got confused here
Nov 1, 2019 09:26
OK
@JohnRennie The application is same right
in both codes
aha got it
what is the prefered way to start coding
c first?
then python
Try this:
def foo():
	print("hai")
	def foo1():
		print("hello")

	print(foo1)
	return foo1

a = foo()
print(hex(id(a)))
hex just converts the decimal number id(a) to hexadecimal to make it easier to compare. This code gives me:
D:\rhs\Python>python test.py
hai
<function foo.<locals>.foo1 at 0x00000213491671F8>
0x213491671f8
So note that id(a) is the same address as foo1
@JohnRennie id of return(foo1) and print(foo1) should be same
Nov 1, 2019 09:31
Yes.
and value retruned is object containg foo1()
now a is reference to foo()
so both should be same
No, a is a reference to foo1 not foo.
When you do a = foo() this executes the function foo() and sets a to the value returned by the function foo().
And because foo() returns the address of foo1 this means a is set to the address of foo1.
and value retruned is object containg foo1()
aha got it
The value returned is the address of the place in memory where foo1 is stored.
@JohnRennie Ah right u have writen return(foo)
foo is a memory location
got it
Nov 1, 2019 09:38
Yes. It's import to understand the difference between return foo1 and return foo1().
return foo1 means return the address in memory where foo1 is stored.
return foo1() means execute the function foo1() and return whatever foo1() returned.
@JohnRennie Hi
let me just explain the code..if i am wrong correct me
in the first code:
fn is passed as reference to the object containing fn()
so what(fn) prints hi
@JohnRennie One doubt.In python everything is passed as reference to the value
Yes. All parameters are actually just the address of the place in memory where the data is stored.
@JohnRennie Can you explain fourth example of image
i think it may not make sense to you i think
Nov 1, 2019 09:52
let me code that up so I can run it ...
fn() is just foo()
so replace them ig
def what(fn):
    def bar():
        fn()
        print("Bruh")

    return bar

def foo():
    print("Rekt")

f = what(foo)
f()
So the function what() returns the address of the function bar. Yes?
So when we do f = what(foo) the variable f gets set to the address of the function bar.
That means when we excute f() we are executing the same code that executing bar() would run.
OK so far?
Nov 1, 2019 09:59
That's it.
@JohnRennie I have a doubt
f = what(foo)
f()
f gets set to address of bar()
Wait don't mind me... I got it
This was a huge help xD.
Thanks a lot!!
Nov 1, 2019 10:14
@JohnRennie Hello
@Aladdin hi
locs = [ [1], [2] ]
for loc in locs:
    loc = []

print(locs)
even if loc is not defined....this works?
no error?
locs = [ [1], [2] ]
print(locs)

for loc in locs:
    loc = []

print(locs)
If I run this (I've added an extra print statement) I get:
D:\rhs\Python>python test.py
[[1], [2]]
[[1], [2]]
yes
for i in locs is same as for loc in locs......i am so stupid
Now try this:
locs = [ [1], [2] ]
print(locs)

for loc in locs:
    print("Before loc = " + str(id(loc)))
    loc = []
    print("After loc  = " + str(id(loc)))

print(locs)
I get:
D:\rhs\Python>python test.py
[[1], [2]]
Before loc = 1957092217416
After loc  = 1957122400200
Before loc = 1957092217928
After loc  = 1957122400200
[[1], [2]]
So when you do loc = [] it is creating a new empty list and assigning the address of that new list to the variable loc. It is not changing the original list.
Nov 1, 2019 10:24
got it
@JohnRennie DO you know about generators
Kind of ...
def mygen():
    	print("one")
    	yield 10
    	print("two")
    	yield 20
    	print("three")
    	yield 30
    	print("four")
f = mygen()
no printing?
The way a generator works is that when you call it it creates an interator but doesn't actually do anything. You need to use a for loop to actually run it.
def mygen():
    print("one")
    yield 10
    print("two")
    yield 20
    print("three")
    yield 30
    print("four")

f = mygen()

for i in f:
    print(i)
D:\rhs\Python>python test.py
one
10
two
20
three
30
four
Nov 1, 2019 10:35
aha let me try
@JohnRennie How can 'i' do print ?
With a generator whenever you call yield it in effect pauses the function at that point and returns the argument to yield.
argument?
So when you call it for the first time it stops at the line yield 10 and returns 10.
oh got it
Then when you call the second time it picks up where it left off, then stops at the line yield 20 and returns 20.
Nov 1, 2019 10:41
aha
all o these can be accesed by for loop
so that' whyu said iteratot
iterator
What the call to mygen() returns is actually an iterator, and the for loop steps through this iterator just like for i in [1,2,3] iterates through the list.
got it
@JohnRennie def mygen():
    	print("one")
    	yield 10
    	print("two")
    	yield 20
    	print("three")
    	yield 30
    	print("four")
mygen()
f=mygen()

res=next(f)
print(res)
Help
what is next doing
Don't call mygen twice. You need to remove the line mygen().
Try this:
def mygen():
    	print("one")
    	yield 10
    	print("two")
    	yield 20
    	print("three")
    	yield 30
    	print("four")

f=mygen()

res=next(f)
print(res)

res=next(f)
print(res)

res=next(f)
print(res)
Nov 1, 2019 10:51
@JohnRennie So it executes until yield statement
no before yield statement
so res=one
but why 10 comes
The next function just steps through an iterator. So each time you call next(f) it returns the next value from the iterator f.
Just like for does.
@Aladdin res isn't one. res is 10, then 20, then 30. The function mygen is printing "one" etc.
i didn't understand...
@JohnRennie Let's go back...
 
Conversation ended Nov 1, 2019 at 10:59.