If I pass the list of cities as a variable, then the task completes as expected.
def count_top_rt(tweet_set):
for tweet in tweet_set:
print(tweet)
tweet_set = ["Sydney", "London", "Paris"]
print(tweet_set)
If I mis-type the argument name in the function definition, then the task still complete, because the tweet_set variable is global.
def count_top_rt(mis_typed_arguament):
for tweet in tweet_set:
print(tweet)
tweet_set = ["Sydney", "London", "Paris"]
print(tweet_set)
It feels like not passing the argument properly is wrong. I have two questions:
- In the first version, is the argument passing 'properly'?
- What are the ways I can make sure to be passing the argument correctly?
3 Answers 3
Is the argument passing 'properly'?
Yes, the argument is passed correctly in the first example: your routine depends only on the input parameter.
What are the ways
In the modular philosophy, you cannot effectively protect against this problem: your function isn't allowed to know about anything external. This is where "pure" modular programming and Python's features are a little bit at odds.
As a programmer, the way to ensure this is to use variable names unlikely to collide. In this case, change the name of tweet_set in the test driver (your main program) to some other name. If this is a standing test case, use a name unlikely to appear in a function, such as TEST_DRIVER_tweet_set.
Programming practices
You can use the search capability in your editor to highlight all occurrences of each name. If you highlight each parameter and variable name in turn and "find all", you can see which ones aren't typed properly.
Advanced technique ... just so you know for "some day" ...
There are Python features that let a function look into the stack, grab the stack frame of the next function (the one that called this one), and check its active variables. If you really, really needed to do so, you could have your function check its own parameter names against variable names in each stack frame, all the way to the main program in the operating system.
There is rarely a case where this is useful.
Comments
There is a simple way of checking that:
>>> def count_top_rt(tweet_set):
... print(id(tweet_set))
... for tweet in tweet_set:
... print(tweet)
>>> tweet_set = ["Sydney", "London", "Paris"]
>>> count_top_rt(tweet_set)
1951490534472
Sydney
London
Paris
>>> id(tweet_set)
1951490534472
>>> tweet_set2 = ["Sydney", "London", "Paris"]
>>> count_top_rt(tweet_set2)
1951490565832
Sydney
London
Paris
>>> id(tweet_set2)
1951490565832
as you can see, when a variable is passed as variable, the local variable becomes a reference to it, no matter what is the name of the global. That is because the interpreter goes to the locals stack first to check for the variable (the reason it is a reference is because of functions' parameters' behavior), only then referring to the globals.
Comments
The best way to prevent this is avoiding global variables. Put all your code into functions and classes.
def count_top_rt(tweet_set):
for tweet in tweet_set:
print(tweet)
def main():
tweet_set = ["Sydney", "London", "Paris"]
count_top_rt(tweet_set)
main()
This will throw a NameError if you misspell the argument name in the definition of count_top_rt.
Comments
Explore related questions
See similar questions with these tags.
forloop is not using the local variable that it's supposed to.