I've been trying to nut out an issue when looping in python 3.
When returning from sub routine the "line" variable has not incremented.
How do I get the script to return the latest readline from the
subsroutine?
Code below
def getData(line):
#print(line)
#while line in sTSDP_data:
while "/service/content/test" not in line:
line = sTSDP_data.readline()
import os, sys
sFileTSDP = "d:/ess/redo/Test.log"
sTSDP_data = open(sFileTSDP, "r")
for line in sTSDP_data:
if "MOBITV" in line:
getData(line) #call sub routine
print(line)
I'm stepping through a large file and on a certain string I need to call
a sub routine to process the next 5 (or 100) lines of data. When the sub routine completes and returns to the main program, it would be better to have it continue on from the last
readline in the sub routine, not the last readline in the main program.
Daan's answer did the trick.
How about using a return statement?
def getData(line):
#print(line)
#while line in sTSDP_data:
while "/service/content/test" not in line:
line = sTSDP_data.readline()
return line
import os, sys
sFileTSDP = "d:/ess/redo/Test.log"
sTSDP_data = open(sFileTSDP, "r")
for line in sTSDP_data:
if "MOBITV" in line:
line = getData(line) #call sub routine
print(line)
Beware the scope of your variables. The 'line' in your getData function is not the same as the 'line' in your loop.
Well, assignment does not work by reference. This means that if you reassign a variable in one function, then it won't modify values in another function (unless there are specific exceptions like global and nonlocal). (Please note: that is reassign, not modify. If you modify a list all references to the list are "modified").
Simply place return line at the end of getData(line)
def getData(line):
#print(line)
#while line in sTSDP_data:
while "/service/content/test" not in line:
line = sTSDP_data.readline()
return line
Related
I'm completly new in python, i'm looking for "thread" a methode from a class.
unfortunately, its seem dificult to understand.
So :
I have a class with methode :
First methode named "readLog" : will read a log file, and return true if it found a specific string (txt)
Second methode named "checkLog" : will check if there is a new one log file, (txt)
I dont know how :
Run this 2 methode in paralelle:
And if readLog found a specific string, call another methode
and in "checkLog" found a new log file, will stop "readlog" process, and start a new one file the new "log path" ( passed in parametre )
You can use threading module to get the similar response
import threading
import os
import time
class SomeClass(object):
def __init__(self):
self.continue_reading = True
def readLog(self, logpath, searchstring):
with open(logpath, "r") as f:
data = f.readlines()
for line in data:
if self.continue_reading:
if searchstring in line:
# Other method here
return line
else:
return None
def checkLog(self, new_filename, directory, searchstring):
# If new file is found
if new_filename in os.listdir(directory):
self.continue_reading = False
# Wait for some time to let the readlog be finished
time.sleep(1)
self.continue_reading = True
th = threading.Thread(
target=self.readLog,
args=(os.path.join(directory, new_filename), searchstring)
)
th.start()
When you call checkLog method, it will spawn new threads for new files, and it will close them as soon as a new-er file is detected.
I would like a variable to be stored in .py file and be imported into a main Python program.
Let me explain the problem in code. In my home folder I have the following files:
testcode.py
testmodule.py
testcode contains the following code:
import pprint
while __name__ == '__main__':
import testmodule
variableFromFile=testmodule.var
print("Variable from file is "+str(variableFromFile))
print("Enter variable:")
variable=input()
Plik=open('testowymodul.py','w')
Plik.write('var='+variable)
Plik.close()
and testmodule contains:
var=0
Now when I launched testcode.py, and input as variables 1,2,3,4,5 I got the following output:
Variable from file is 0
Enter variable:
1
Variable from file is 0
Enter variable:
2
Variable from file is 0
Enter variable:
3
Variable from file is 0
Enter variable:
4
Variable from file is 0
Enter variable:
5
Variable from file is 0
Enter variable:
But I would like to refresh this variable every time it is printed on screen, so I expect in this line:
print("Variable from file is "+str(variableFromFile))
to update the variable's value. Instead, I get in output only the first value of the variable, so the program print 0 every time. Only restarting the program will refresh the value of var.
Is there a way to import variables from file, change them at runtime and then then use their updated values later on in the script?
I believe your basic problem stems from the use of the variable in the testmodule.py file. As written you code imports this file and thus the pyhton interpreter assigns the value of testmodule.var to the contents thyat exist at load time. The code which attempts to update the variable isn't working the way you intended, since Plik.write('var='+variable) is creating a text string of the form "var = n". Thus subsequent attempts to import the testmodule and get the testmodule.var variable will result in a 0 value.
To fix this problem, as suggested by #JONSG, requires you abandon the import context and do something along the lines of the following:
#Contents of testmodule.txt file
0
#Contents of the testcode.py file
def readVar(fn):
with open(fn, 'r') as f:
return f.read().strip()
def writeVar(fn, val):
with open(fn,'w') as f:
f.write(val)
def runcode():
varfile = 'testmodule.txt' #Assumes testmodule.txt is in same folder as code
variableFromFile= readVar(varfile)
print("Variable from file is "+str(variableFromFile))
variable=input("Enter variable: ")
writeVar(varfile, variable)
def main():
runcode()
if __name__ == "__main__":
main()
Now every time you run the file, the latest variable data will be loaded and then updated with a new value.
This is my code:
import os
if os.path.exists(r'C:\Genisis_AI'):
print("Main File path exists! Continuing with startup")
else:
createDirs()
def createDirs():
os.makedirs(r'C:\Genisis_AI\memories')
When I execute this, it throws an error:
File "foo.py", line 6, in <module>
createDirs()
NameError: name 'createDirs' is not defined
I made sure it's not a typo and I didn't misspell the function's name, so why am I getting a NameError?
You can't call a function unless you've already defined it. Move the def createDirs(): block up to the top of your file, below the imports.
Some languages allow you to use functions before defining them. For example, javascript calls this "hoisting". But Python is not one of those languages.
Note that it's allowable to refer to a function in a line higher than the line that creates the function, as long as chronologically the definition occurs before the usage. For example this would be acceptable:
import os
def doStuff():
if os.path.exists(r'C:\Genisis_AI'):
print("Main File path exists! Continuing with startup")
else:
createDirs()
def createDirs():
os.makedirs(r'C:\Genisis_AI\memories')
doStuff()
Even though createDirs() is called on line 7 and it's defined on line 9, this isn't a problem because def createDirs executes before doStuff() does on line 12.
I was trying following python code to simulate 'tail' command of *nix systems.
import sys
def tail(f):
print 'in tail with ',f
f.seek(0,2)
while True:
line = f.readline()
if not line:
time.sleep(0.1)
continue
yield line
if(len(sys.argv) >= 2):
print 'calling tail'
tail(open(sys.argv[1],'r'))
else:
print 'Give file path.\n'
I did an error (missed importing time module). However, what's odd is that no error was getting thrown and program was quitting silently.
Output (before commenting):
$ python tail.py /var/log/dmesg
calling tail
However if I comment lines following the one using the time module, the error does get thrown.
import sys
def tail(f):
print 'in tail with ',f
f.seek(0,2)
while True:
line = f.readline()
if not line:
time.sleep(0.1)
# continue
# yield line
if(len(sys.argv) >= 2):
print 'calling tail'
tail(open(sys.argv[1],'r'))
else:
print 'Give file path.\n'
Output (after commenting)
$ python tail.py /var/log/dmesg
calling tail
in tail with <open file '/var/log/dmesg', mode 'r' at 0x7fc8fcf1e5d0>
Traceback (most recent call last):
File "tail.py", line 14, in <module>
tail(open(sys.argv[1],'r'))
File "tail.py", line 8, in tail
time.sleep(0.1)
NameError: global name 'time' is not defined
Can anyone please explain why the error was not getting thrown in case one (before commenting)? Shouldn't a error be thrown as soon as interpreter comes on that line?
Corrected program:
import sys
import time
def tail(f):
print 'in tail with ',f
f.seek(0,2)
while True:
line = f.readline()
if not line:
time.sleep(0.1)
continue
yield line
if(len(sys.argv) >= 2):
print 'calling tail'
t = tail(open(sys.argv[1],'r'))
for i in t:
print i
else:
print 'Give file path.\n'
Output:
$ python tail.py hello.txt
calling tail
in tail with <open file 'hello.txt', mode 'r' at 0x7fac576b95d0>
hello there 1
hello there 2
hello there 3
Thanks for the responses.
Short Answer
First one is instantiating a generator (but not assigning it to a variable) and second one is a function call.
Long Answer
This is because of dynamic type checking of python, when you have the yield statement, your function behaves as a generator and this line -
tail(open(sys.argv[1],'r'))
means that you are instantiating the generator not calling a function. You'll get that error when you assign this instance to some variable and call the next method for generator which actually fires it up i.e. -
t = tail(open(sys.argv[1],'r')) # t is a generator here
t.next()
The other case in which you removed the yield statement, it started behaving as a normal function which means - tail(open(sys.argv[1],'r')) is a function call now, and hence it threw an error.
What I meant by dynamic is python doesn't check these kind of errors until it reaches that statement, which in first case wasn't.
With yield in the function, it is a generator. Generator functions only execute their contained code when the next value is requested. Simply calling a generator function merely creates that generator object. If you do so without doing anything with that object, such as looping through it, nothing will happen.
Removing the yield makes the function evaluate eagerly, so its code is actually executed.
If you actually iterated over the generator, it would produce an error if/when readline() produced an empty line. Since such an empty line can only occur at the end of a file (what look like blank lines actually contain a single linefeed character), putting it in a loop doesn't make sense anyway. Instead of this:
while True:
line = f.readline()
if not line:
time.sleep(0.1)
continue
yield line
Use this:
for line in f:
yield line
And instead of this:
if(len(sys.argv) >= 2):
print 'calling tail'
tail(open(sys.argv[1],'r'))
You should actually execute the generator's contents, with something like this:
if(len(sys.argv) >= 2):
print 'calling tail'
for line in tail(open(sys.argv[1],'r')):
print line
I am using the cmd.Cmd class in Python to offer a simple readline interface to my program.
Self contained example:
from cmd import Cmd
class CommandParser(Cmd):
def do_x(self, line):
pass
def do_xy(self, line):
pass
def do_xyz(self, line):
pass
if __name__ == "__main__":
parser = CommandParser()
parser.cmdloop()
Pressing tab twice will show possibilities. Pressing tab again does the same.
My question is, how do I get the options to cycle on the third tab press? In readline terms I think this is called Tab: menu-complete, but I can't see how to apply this to a Cmd instance.
I already tried:
readline.parse_and_bind('Tab: menu-complete')
Both before and after instantiating the parser instance. No luck.
I also tried passing "Tab: menu-complete" to the Cmd constructor. No Luck here either.
Anyone know how it's done?
Cheers!
The easiest trick would be to add a space after menu-complete:
parser = CommandParser(completekey="tab: menu-complete ")
The bind expression that is executed
readline.parse_and_bind(self.completekey+": complete")
will then become
readline.parse_and_bind("tab: menu-complete : complete")
Everything after the second space is acutally ignored, so it's the same as tab: menu-complete.
If you don't want to rely on that behaviour of readline parsing (I haven't seen it documented) you could use a subclass of str that refuses to be extended as completekey:
class stubborn_str(str):
def __add__(self, other):
return self
parser = CommandParser(completekey=stubborn_str("tab: menu-complete"))
self.completekey+": complete" is now the same as self.completekey.
Unfortunately, it seems as though the only way around it is to monkey-patch the method cmdloop from the cmd.Cmd class, or roll your own.
The right approach is to use "Tab: menu-complete", but that's overriden by the class as shown in line 115: readline.parse_and_bind(self.completekey+": complete"), it is never activated. (For line 115, and the entire cmd package, see this: https://hg.python.org/cpython/file/2.7/Lib/cmd.py). I've shown an edited version of that function below, and how to use it:
import cmd
# note: taken from Python's library: https://hg.python.org/cpython/file/2.7/Lib/cmd.py
def cmdloop(self, intro=None):
"""Repeatedly issue a prompt, accept input, parse an initial prefix
off the received input, and dispatch to action methods, passing them
the remainder of the line as argument.
"""
self.preloop()
if self.use_rawinput and self.completekey:
try:
import readline
self.old_completer = readline.get_completer()
readline.set_completer(self.complete)
readline.parse_and_bind(self.completekey+": menu-complete") # <---
except ImportError:
pass
try:
if intro is not None:
self.intro = intro
if self.intro:
self.stdout.write(str(self.intro)+"\n")
stop = None
while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
if self.use_rawinput:
try:
line = raw_input(self.prompt)
except EOFError:
line = 'EOF'
else:
self.stdout.write(self.prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
line = 'EOF'
else:
line = line.rstrip('\r\n')
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
finally:
if self.use_rawinput and self.completekey:
try:
import readline
readline.set_completer(self.old_completer)
except ImportError:
pass
# monkey-patch - make sure this is done before any sort of inheritance is used!
cmd.Cmd.cmdloop = cmdloop
# inheritance of the class with the active monkey-patched `cmdloop`
class MyCmd(cmd.Cmd):
pass
Once you've monkey-patched the class method, (or implemented your own class), it provides the correct behavior (albeit without highlighting and reverse-tabbing, but these can be implemented with other keys as necessary).