Python Forum
Class Modules, and Passing Variables: Seeking Advice
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Class Modules, and Passing Variables: Seeking Advice
#11
(Mar-01-2018, 02:25 PM)Robo_Pi Wrote: I would also like to learn more about how to create and implement a configuration file that Gribouillis had suggested for the file path names and global variables.
Here is a way to do this. You first create a configuration file such as this one
Output:
# alysha.conf [tasks] command_file = C:/100_Robo_pass/Commands.txt
This file can be somewhere on your filesystem such as YOURHOMEDIR/.config/alysha.d/alysha.conf

Your program can then read the configuration file by using python's configparser module. For python 2 it reads
from ConfigParser import SafeConfigParser
import os
from os.path import join as pjoin

conf_filename = pjoin(
    os.path.expanduser('~'), '.config', 'alysha.d', 'alysha.conf')

conf = SafeConfigParser()
conf.read(conf_filename)

command_filename = conf.get('tasks', 'command_file')
The location of the configuration file can be fined-tuned later, for example the program can have a command line option to override the default location, different locations can be tried such as the current working directory or some other standard place. The above code gives you a simple start to using a configuration file for your application. You can also read this overview of configparser.
Reply
#12
Some more points/advice.
Don't use * import.
Try not have blank lines in code,only between function/methods.
I don't like main() as it can be given a name that has some meaning.
Naming stuff it difficult,i like keep names reasonable short and docstring can come in and help with explanation.
Just to show something in the style i talk about.
A styled up(CSS) PEP-8 Wink

alysha.py:
class Alysha():
    def __init__(self):
        pass

    def read(self):
        tasks = ['Task 1', 'Task 2', 'Task 3', 'Task 4', 'Task 5']
        return tasks

    def write(self, message):
        return('\n{}\n'.format(message))
from alysha import Alysha

def meaningful_name():
    '''Docstring explain what function do'''
    task = Alysha()
    print(task.read())
    print(task.write('Something'))

if __name__ == '__main__':
    meaningful_name()
Output:
['Task 1', 'Task 2', 'Task 3', 'Task 4', 'Task 5'] Something
Reply
#13
@snippsat,

I've been trying to change the name of main() and couldn't make it work. I finally realized that I need to also change the name at the bottom if statement too. Now that I've done that I was able to change the name of main(). I changed it to Alysha() which is what I wanted it to be all along.

And yes, I'm using extensive doc strings. If you look at the OP you can see just how extensive I get with them. I've removed them for simplicity in this thread. I'm big on comments. I write far more comments than code.

Also I can't get "from alysha import Alysha" to work. I've tried everything I can think of.

In my case it would actually be:

from alysha_pass import AlyshaPass
But that won't work. The only thing I can get to run is:

from alysha_pass.AlyshaPass import *
That's only thing that will run.

Everything else produces a "Can't find the module AlyshaPass" error

Actually the error I get when using the following import format is:
Module not callable.

from alysha_pass import AlyshaPass
But if I used the following: Then everything works.

from alysha_pass.AlyshaPass import *
I would actually prefer to use the more specific format, but I can't get it to work.
Reply
#14
(Mar-01-2018, 07:21 PM)Robo_Pi Wrote: But that won't work. The only thing I can get to run is:
It is because you want to access the class AlyshaPass in module AlyshaPass. You can do
from alysha_pass.AlyshaPass import AlyshaPass
ap = AlyshaPass()
The module and the class are two different objects.
Reply
#15
(Mar-01-2018, 08:11 PM)Gribouillis Wrote:
(Mar-01-2018, 07:21 PM)Robo_Pi Wrote: But that won't work. The only thing I can get to run is:
It is because you want to access the class AlyshaPass in module AlyshaPass. You can do
from alysha_pass.AlyshaPass import AlyshaPass
ap = AlyshaPass()
The module and the class are two different objects.

Ok, that works!

So now I need to better understand the difference between a module and a class.

I have no clue what I'm doing. It's a miracle I can get this stuff to work at all.
Reply
#16
What I posted earlier is correct.
You have changed it.

it should read:
import AlyshaPass
task = AlyshaPass.AlyshaPass()
the whenever you are calling a method in AlyshaPass, use
task.read()
Reply
#17
(Mar-01-2018, 09:55 PM)Larz60+ Wrote: What I posted earlier is correct.
You have changed it.

it should read:
import AlyshaPass
task = AlyshaPass.AlyshaPass()
the whenever you are calling a method in AlyshaPass, use
task.read()

Thanks for the suggestion.

I prefer to use names that have meaninging for me.

So I have chosen to rewrite my main program as follows:

  1. First I've changed main() to Alysha() because that's what I want this to be called.
  2. I took your advice and used the specific import format.
  3. I then set the class name to the pointer AlyshaPass
  4. I'm using title case for this to remind me that this is pointing to a class
  5. This removes the need to use parentheses after AlyshaPass in the actual calls.
  6. I don't want to use just "ap", or "task" for this pointer because I'll forget what that means.
  7. When I see AlyshaPass.something I'll know that this is pointing to the AlyshaPass() class.
  8. According to PEP 8 style convention class names are supposed to be capitalized.

So I'm very happy with this code as written below and it seems to work just fine.

from alysha_pass.AlyshaPass import AlyshaPass
AlyshaPass = AlyshaPass()


def Alysha():
		# get tasks
	tasks = AlyshaPass.read()
	print tasks
		
		# write reply
	AlyshaPass.write("Dummy Message")
	
	
		# for documentation purposes
	help(AlyshaPass.read)
	help(AlyshaPass.write)
	
		# Just a temporary break for debugging
	a = int(raw_input("Press enter:"))
	
	return 0
if __name__ == '__main__':
	Alysha()
 

Just in case anyone is interested in the full project here's the modified AlyshaPass.py module

Just as a heads-up I've changed the following items:

  1. The text file I'm working with is now called tasks.txt (formerly commands.txt)
  2. The file_path and name are also now defined in Alysha() and passed to AlyshaPass.read()
  3. In the actual read() method I'm made some major changes.
  4. The main change was to add the ability to pass in the file_path.
  5. Basically I do everything on a single line now (line 37 in the code below)
  6. I've also renamed the variables to "words" instead of "tasks"
  7. The reason for this is that I now see where I can make this a more generalized method.
  8. Also hopefully everything has been cleaned up to meet PEP 8 style conventions.

AlyshaPass.py

class AlyshaPass():
	'''
	---- AlyshaPass class ---
	Contains read() and write() methods for reading and writing text files.
	'''
	
	def __init__(self):
		'''
		Not currently using the inititation method.
		'''
		pass
	
	def read(self, file_path):
		'''
		
		---- AlyshaPass.read() method to read the file_path.txt file ----
		This program reads the text file pointed to by file_path
		It then converts text into a Python List named "words".
		and then passes the list back to the calling program using return (words)
		'''
			# ---------- Begin Reading file_path.txt Routine --------------
			
			# Create a raw string array to hold entire file contents. 
			# Required to be able to count how many words there are.
		words_raw = []
			# Create a new string array to hold the individual words.
		words = []
			# Read the file_path.txt file using the Ptyhon "open" function.
			# Create a file-reading object named "stream_reader"
		stream_reader = open(file_path, 'r')
			# Read in the entire file contents into a temporary varible.
		words_raw = stream_reader.readlines()
			# len(words_raw) is the number of words in the file.
		for i in range(0,len(words_raw)):
				# Strip off the carriage returns and line feed,...
				# and create the indexed words[i] list of words.
			words.append(words_raw[i].strip())
			# Close the file!	
		stream_reader.close
			# Pass the words list back to the calling program.
		return (words)
			
	def write(self, message):
		'''
		
		---- AlyshaPass.write() method will write to a text file ----
		The name of the file is optional and may even include multiple names.
		'''
		print "\n" , message , "\n"
			
	
Reply
#18
At line 39 you're not calling the close method! Use close(). Note that the read method can be shrunk to
def read(self, file_path):
    with open(file_path, 'r') as stream_reader:
        return [line.strip() for line in stream_reader if line.strip()]
close() is run automatically at the end of the with block. This code also removes blank lines if any.
Reply
#19
(Mar-02-2018, 07:04 AM)Gribouillis Wrote: At line 39 you're not calling the close method! Use close().

Thanks for catching that! None of my IDE's caught that. And it doesn't seem to have caused any problems running the program. It doesn't appear to lock the file as open anyway. None the less I'm glad you caught that. I fix that right away.

(Mar-02-2018, 07:04 AM)Gribouillis Wrote: Note that the read method can be shrunk to
def read(self, file_path):
    with open(file_path, 'r') as stream_reader:
        return [line.strip() for line in stream_reader if line.strip()]

Yes, I'm aware that there are endless clever ways to do things using minimal coding. I have mental problems and cannot think as clearly as I used to. So I like to write my code out in a way where I can explain everything I'm doing in comments. So I'll often chose to write things out in code the way I'm thinking about them, rather than just trying to do everything on one line. I didn't mind writing words.append(words_raw[i].strip()) because that's pretty clear what's going on.

But on the return line I like to have return (words), because that instantly tells me precisely what I'm returning. I can see that I'm returning the list named "words". And I may have other data that I might return as the program grows. So I like to keep the return statement containing only the names of the variable types I'm actually returning. This way I can just glance at the return statements in a method and instantly see what the method returns.

This is my own personal coding convention that I've always followed. I'm new to Python, but I've been programming in other languages for years. So I have my own style that I stick with.

(Mar-02-2018, 07:04 AM)Gribouillis Wrote: close() is run automatically at the end of the with block. This code also removes blank lines if any.

Yes, I've been thinking of going with the with statement. But again, I have traditionally always preferred to manually close files that I open. This tells me more clearly in the code precisely where I'm done working with the file. In fact, I should actually move the stream_reader.close() up to just before the for loop, because I'm actually done reading the file at that point.

My code would then look like this: (moving stream_reader.close() up to the point where I'm actually done reading the file. Everything I do after that no longer requires the file to be open.

            # ---------- Begin Reading file_path.txt Routine --------------
             
            # Create a raw string array to hold entire file contents. 
            # Required to be able to count how many words there are.
        words_raw = []
            # Create a new string array to hold the individual words.
        words = []
            # Read the file_path.txt file using the Ptyhon "open" function.
            # Create a file-reading object named "stream_reader"
        stream_reader = open(file_path, 'r')
            # Read in the entire file contents into a temporary varible.
        words_raw = stream_reader.readlines()
            # Close the file   
        stream_reader.close()
            # len(words_raw) is the number of words in the file.
        for i in range(0,len(words_raw)):
                # Strip off the carriage returns and line feed,...
                # and create the indexed words[i] list of words.
            words.append(words_raw[i].strip())
            # Pass the words list back to the calling program.
        return (words)
Note: I want my code to be easily readable to even the most neophyte programmer. So making the code easy to understand is my goal. I have no need to make it compact.

I have also chosen to indent all of my comments from the main code block. I do this because I have failing eyes and when the comments are lined up with the code it's hard for me to see which lines are comments and which lines are code. So I just indent all the comment lines and this leaves the actual code lines sticking out where they are easy to notice.
Reply
#20
(Mar-02-2018, 02:21 PM)Robo_Pi Wrote: I want my code to be easily readable to even the most neophyte programmer. So making the code easy to understand is my goal. I have no need to make it compact.
concise code is always better and much easier to follow :-)

(Mar-02-2018, 02:21 PM)Robo_Pi Wrote: I have also chosen to indent all of my comments from the main code block. I do this because I have failing eyes and when the comments are lined up with the code it's hard for me to see which lines are comments and which lines are code. So I just indent all the comment lines and this leaves the actual code lines sticking out where they are easy to notice.
good for you as for the rest of us this is not the case. For me it's more difficult
You tend to repeat in plain language every line of code (even the most simple one like opening a file) and that is a real pain. Just my 2 cents
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Seeking advice on dask distributed sawtooth500 4 264 Apr-15-2024, 11:07 PM
Last Post: sawtooth500
  Unchangeable variables in a class? Calab 12 1,541 Sep-15-2023, 07:15 PM
Last Post: deanhystad
  Class variables and Multiprocessing(or concurrent.futures.ProcessPoolExecutor) Tomli 5 3,892 Nov-12-2021, 09:55 PM
Last Post: snippsat
  How to pass variables from one class to another hobbyist 18 10,720 Oct-01-2021, 05:54 PM
Last Post: deanhystad
  Acess variables from class samuelbachorik 3 1,899 Aug-20-2021, 02:55 PM
Last Post: deanhystad
  Passing Variables between files. victorTJ 3 2,251 Oct-17-2020, 01:45 AM
Last Post: snippsat
  New user seeking help EdRaponi 2 44,655 Jun-23-2020, 12:03 PM
Last Post: EdRaponi
  Class variables menator01 2 2,008 Jun-04-2020, 04:23 PM
Last Post: Yoriz
  Question about naming variables in class methods sShadowSerpent 1 2,010 Mar-25-2020, 04:51 PM
Last Post: ndc85430
  Python 2.7 passing variables from functions zetto33 1 1,783 Mar-19-2020, 07:27 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020