2

I've been searching online for a while now and can't seem to find anything. I'm basically learning a few languages and I am just trying to recreate a program in different languages.

def read_one_file():
    f = open('C:\Python27\inventory.dat', 'r')
    invid = f.readline()
    stock = f.readline()
    published = f.readline()
    price = f.readline()
    invtype = f.readline()
    title = f.readline()
    author = f.readline()
    return invid, stock, published, price, invtype, title, author

read_one_file()

print "Update Number In Stock"
print "----------------------"
print "Item ID: ", invid

Basically I'm trying to read in a file, absorb the data into variables then pass those variables to the main(class?). When I return them they're still not able to be printed. When I initialize them outside of read_one_file they still don't return the right thing.

5 Answers 5

5

You need to store the results of read_one_file() somewhere. What you're really doing with your return statement is creating a tuple of the results. You then have to unpack that tuple when you call read_one_file. Here is an example:

(invid, stock, published, price, invtype, title, author) = read_one_file()

print "Item ID:", invid

This syntax is performing something called "pattern matching" and what it does is break up the tuple that read_one_file returns and gives names to each of element in it. I added the parenthesis here to make it clearer that read_one_file is returning a tuple, but you could just as easily write it like this:

invid, stock, published, price, invtype, title, author = read_one_file()

That's all well and good, but really, this is sort of a bad way to return things from your function. If you have a lot of variables you want to return from a function like this, a dict is probably a better way to go. Also, you'll probably want to use a with statement to ensure your file is closed and cleaned up properly once you're done with it. Here is what your code would look like using that strategy:

def read_one_file():
    with open('C:\Python27\inventory.dat', 'r') as f:
        return dict(invid = f.readline().strip(),
                    stock = f.readline().strip(),
                    published = f.readline().strip(),
                    price = f.readline().strip(),
                    invtype = f.readline().strip(),
                    title = f.readline().strip(),
                    author = f.readline().strip())

results = read_one_file()

print "Update Number In Stock"
print "----------------------"
print "Item ID: ", results['invid']

Edit: I changed the code above to use .strip(), since (as @NiklasB. pointed out), newlines are still included with just readline.

Sign up to request clarification or add additional context in comments.

11 Comments

That's not too DRY... Also it preserves all the newlines present in the file.
+1 for answering the question in a way the answerer can understand. Let's not get too far ahead of the audience, @NiklasB.
Well, I was going more from a 'here are a few upgrades you can make to your code' so that he wouldn't have to look up too much to understand it. Unpacking, with statements and dicts might all be new to him, so I went with the most obvious improvements coming from the code he'd already written.
@mattbornski: I disagree very much. This is not tech-support, we are trying to actually teach people proper coding here. "Value for future visiters" etc. This could be made much shorter using a dict comprehension (see wim's answer).
@NiklasB. The value for future visitors is coming from the fact that future visitors hitting upon this question will be similarly new to Python. If someone understands python well enough to get list comprehensions and itertools, they probably won't be looking for something this question answers. But I agree about the newlines, I'll tweak the code a bit
|
5

This is a bit cleaner for what you seem to be trying to do. Note I'm assuming your inventory.dat file isn't really huge, and has at least 7 lines.

def read_one_file(fname=r'C:\Python27\inventory.dat'):
    with open(fname) as f:
        lines = [line.strip() for line in f]
    keys = ['invid', 'stock', 'published', 'price', 'invtype', 'title', 'author']
    inventory_item = dict(zip(keys, lines[:len(keys)]))
    return inventory_item

d = read_one_file()

print("Update Number In Stock")
print("----------------------")
print("Item ID: ", d['invid'])

Breakdown of changes from your original code:

  • fname passed as default argument, rather than hardcoded into the function
  • fname string made into a r'raw string' with the r prefix, which would prevent backslash escapes from being handled wrongly (image for example if your filename was ninventory.dat, with the \ as a path separator in windows you would get a newline in the filename if you were using a normal string)
  • file opened with context manager, to ensure it is closed properly. Read about Python's with statement for details.
  • [line.strip() for line in f] is a list comprehension to remove the trailing newlines from your data and store the lines in a list called lines.
  • list of keys defined, and then the first n lines of the file are mapped as the values of the keys, using a python dict.
  • lines[:len(keys)] slices the list to the first n items, where n is the number of keys declared above.
  • zip just pairs up 2 iterables (in this case keys and the values from file) into an iterable of tuples, which is one of the accepted forms when creating a new dict.
  • d = read_one_file() stores the result of the file read into a variable. in your code this was being lost because there was no reference to the return value of the function held.
  • d['invid'] accesses the value of the key 'invid' stored in the dict d. you should access the other values similarly.

1 Comment

Would you mind breaking this down. It's quite hard for a novice to decipher.
1

This should work:

def read_one_file():
    f = open('C:\Python27\inventory.dat', 'r')
    invid = f.readline()
    stock = f.readline()
    published = f.readline()
    price = f.readline()
    invtype = f.readline()
    title = f.readline()
    author = f.readline()
    return invid, stock, published, price, invtype, title, author

invid, stock, published, price, invtype, title, author = read_one_file()

print "Update Number In Stock"
print "----------------------"
print "Item ID: ", invid

Basically, you're returning what's called a "tuple" of variables from the function and assigning it to a "tuple" of variables in the main program. The fact that they are named the same thing is not really important to the program.

4 Comments

So is returning them as a tuple okay? Or should I make an array(list in python?).
Alright, but how do I print them later on? Not sure If I'm asking the right question... how can the tuple be split, I guess, so I can use them independently. EDIT: I just got it. I can put invid = read_one_file
For more details I'll refer you to the docs, specifically this line from section 5.3 of the tutorial titled "Data Structures": "Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence." docs.python.org/tutorial/datastructures.html
@Nogg: IMHO, his solution is suboptimal, it does not cleanly separate the file handling logic from the data modelling and has a lot of code repetition. For example, you really shouldn't represent integer values as strings in your program. Also, the newlines read by readline are included into the data strings. Furthermore, as already mentioned, it leaks an open file.
1

Another option is to pass a dictionary in the function call, and then access the variables from the dict:

read_file_dict = {}

def read_one_file(some_dict):
    ...
    some_dict['invid'] = file.readline()
    some_dict['stock'] = file.readline()
    ...

Run the function:

read_one_file(read_file_dict)

And then access the variables (dict entries):

read_file_dict['invid']

Comments

0

The short answer: As others have stated, you need to unpack the tuple you're returning, and then the values will be available to you:

    invid, stock, published, price, invtype, title, author = read_one_file()

The long answer: This might be a tad long, but bear with me, because it is important information in understanding how various programming languages work. The problem you're having is an understanding of scope, the lifetime of variables in certain scopes, and how variables can be transferred between two different scopes. I'll do my best to touch on each of these, and how it relates to your problem.

Scope is essentially a section of your program in which certain variables you declare will exist. When you defined the function:

    def read_one_file():
        f = open('C:\Python27\inventory.dat', 'r')
        invid = f.readline()
        stock = f.readline()
        published = f.readline()
        price = f.readline()
        invtype = f.readline()
        title = f.readline()
        author = f.readline()
        return invid, stock, published, price, invtype, title, author

you defined the scope. The variables invid, stock, published, price, invtype, title, and author all exist in that function, and cease to exist once that function terminates. Python happens to be a very good visualizer of scope, since it is space/tab dependent. A new indentation level defines a new scope.

In order to get a variable/value out of the scope of a function, you can return it, as you have done in your function. But the portion of your program which is calling the function, has to specify variables in its own scope which will receive the values the function is returning. (And to receive the data, you assign the variable to result of the function: var = function() )

In your posted code, you called read_one_file() but did not assign any variables to its returned values. When you tried to access one of the values you thought you were returning:

    print "Update Number In Stock"
    print "----------------------"
    print "Item ID: ", invid

invid is not technically a variable outside of read_one_file(), so an error occurs.

The key is that returning variables does not automatically transfer them, by name, to the scope of the callee (the code calling the function). You must specify a new variable in the callee to receive the returned value.

Hope this helps :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.