简体   繁体   中英

Passing variables in Python

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.

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.

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.

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.

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']

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 :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM