Python Forum
calling external function with arguments
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
calling external function with arguments
#1
I am new to python...

I am trying to call a function defined in a separate program, but I cannot figure out how to pass an argument. How to do?

The function I want to call is in this program:
testren.py:
import sys, getopt global old_name def renameit(argv): global old_name old_name = '' opts, args = getopt.getopt(argv,"ho:",["oldname="]) for opt, arg in opts: if opt in ("-o", "--old_name"): old_name = arg print ('in testren after - old_name =', old_name ) if __name__ == "__main__": print ('sys.argv ', sys.argv[1:]) renameit(sys.argv[1:])
If I call testren.py directly, I get the desired results:
Output:
C:\python>python testren.py -o "my1.mp3" sys.argv ['-o', 'my1.mp3'] in testren after - old_name = my1.mp3
If I call it from another python program the arguments are not found, I cannot figure out how to pass the arguments. How to do?

calltestren.py:
import testren if __name__ == '__main__': renargs = '-o "my1.mp3"' print('calling rename', renargs) testren.renameit(renargs) print('old_name<', old_name, '>')
I just get blanks where I expect a file name to be:
Output:
C:\python>python calltestren.py calling rename -o "my1.mp3" in testren after - old_name = old_name< >
Reply
#2
Some remarks first:
  1. Avoid using the global keyword as much as possible, it makes better code. Seasoned pythonistas use this keyword very infrequently.
  2. Don't use the getopt module, use the more flexible argparse module instead. Getopt just mimics the old getopt library of the C language. I think it is still here mostly for backward compatibility.
  3. The function renameit expects its first argument to be a list of strings, don't give it a simple string.
Here is the corrected code
# testren2.py import argparse import sys def renameit(argv): parser = argparse.ArgumentParser() parser.add_argument( '-o', '--old-name', help="old name", dest='old_name', required=True) args = parser.parse_args(argv) print ('in testren after - old_name =', args.old_name ) if __name__ == "__main__": print ('sys.argv ', sys.argv) renameit(sys.argv[1:])
and the code that calls it
# calltestren2.py import testren2 as testren if __name__ == '__main__': renargs = ['-o', 'my1.mp3'] # note this is a list of strings, not a single string! print('calling rename', renargs) testren.renameit(renargs)
snippsat likes this post
Reply
#3
(Jun-23-2023, 04:43 AM)Wimpy_Wellington Wrote: If I call it from another python program the arguments are not found, I cannot figure out how to pass the arguments. How to do?
I may think there is confusion about using command line tool sys.argv, getopt(do not use as mention).
Because you don't use command line here at all,but try to call it from a other module using a string.

argparse Gribouillis show is ok,but can show a example with Typer which is really cool.
Here i also do rename on files on disk,not just show there names.
from pathlib import Path import typer app = typer.Typer() @app.command() def renameit( old_name: str = typer.Option(..., '-o', '--old-name'), new_name: str = typer.Option(..., '-n', '--new-name'), ): old_path = Path(old_name) if old_path.is_file(): old_path.rename(Path(new_name)) typer.echo(f'File renamed from {old_name} to {new_name}') else: typer.echo('File not found.') if __name__ == '__main__': app() 
Using it,see that help and colors get(use Rich under the hood) get generated automatic.
[Image: ATaLiF.png]
Also using this in a other module only need to pass app,and it will work.
from rename_files import app if __name__ == '__main__': app()
Reply
#4
I don't know about the theoretical aspects of programming, or technical stuff. For me Python is just a practical tool. Get the job done as simply as possible.

I have a folder: /home/pedro/myPython/myModules/ where, unsurprisingly, I keep my homemade modules.

If I make this module and save it in /home/pedro/myPython/myModules/ as change_file_names.py:

import os def change_name(a,b): os.rename(a, b) print('Changed the name of', a, 'to', b)
Then I can call it anytime:

#! /usr/bin/python3 # do this because I don't add the path to my modules to the system PATH variable import sys sys.path.append('/home/pedro/myPython/myModules/') # if you add the path to your homemade modules to your system PATH, you can forget the 2 lines above import change_file_names as cfns if __name__ == "__main__": cfns.change_name('/home/pedro/temp/a.txt', '/home/pedro/temp/b.txt')
I'm sure the suggestions from Gribouillis and snippsat are technically much better, but it's hard for me to understand what's going on, it's all very cryptic.

Also, if the trusty old steed os can do the job, why complicate matters? Just use os.
Reply
#5
(Jul-04-2023, 11:18 PM)Pedroski55 Wrote: sys.path.append('/home/pedro/myPython/myModules/')
@Pedroski55 you could write this line in a (new?) file named usercustomize.py in the directory returned by site.getusersitepackages()
This would spare you the effort to write this line in all your scripts.

Also the PATH variable is for executable programs, not for Python modules.
Reply
#6
Aha! Technical stuff! Thanks!

That was easier than I thought:

import site site.addsitedir('/home/pedro/myPython/myModules/')
Then this works fine:

import change_file_names as cfns if __name__ == "__main__": cfns.change_name('/home/pedro/temp/b.txt', '/home/pedro/temp/a.txt')
But I prefer

import os os.rename('/home/pedro/temp/a.txt', '/home/pedro/temp/b.txt')
Reply
#7
Why is testren.py a module? It is not reusable code. How can a different Python program use this code? There are reusable command line parsers (typer was mentioned. I like argparse for simple command lines. There are others) that let you parse arbitrary command lines. Why write a module for doing this? I can understand writing this as a function in your main program, but it makes no sense as a module.

Never use global variables to return values from a function. Use the return statement. The less you have to know about a function/module to use it, the better. Your users should not have to call a function and then access a global variable to get the result. That forces them to know 3 things (function, variable, connection between the two). Your function should return the value directly, so your users only need to know about the function.

Maybe I am reading this wrong and renameit() is supposed to be a reusable function that does something useful (like rename a file from old_name to new_name). If that is the case, you should pass function arguments, not command line arguments. You can also write your module so it lets you call renameit() from the command line. This is a simple example.

renameit.py
import sys # This is the reusable function I want to export. def renameit(old_name, new_name): """Does something interesting or useful with old_name and new_name.""" print(f"renameit({old_name}, {new_name})") # This lets me execute the function from the command line. if __name__ == "__main__": args = sys.argv[1:] if len(args) != 2: print("Missing arguments for renameit file new_name") else: renameit(*args)
Importing and using the renameit function.
from renamit import renameit renamit("name of old thing", "the new name")
Here I added an optional argument and use argparse to parse the command line.
import argparse def renameit(old_name, new_name, version=None): """Does something interesting or useful with old_name and new_name.""" print(f"renameit({old_name}, {new_name}, version={version})") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Give an old thing a new name.") parser.add_argument("old_name", type=str, help="name of existing thing") parser.add_argument("new_name", type=str, help="new name for thing") parser.add_argument( "-v", "--version", action="store_true", help="add version number of new name clashes with existing thing", ) args = parser.parse_args() renameit(args.old_name, args.new_name, args.version)
Now I can ask for help on how to use the function from the commandline.
Output:
: python renameit -h usage: renameit.py [-h] [-v] old_name new_name Give an old thing a new name. positional arguments: old_name name of existing thing new_name new name for thing options: -h, --help show this help message and exit -v, --version add version number of new name clashes with existing thing
And if I mess up entering the arguments I get an informative error message.
Output:
: python renameit.py -v "name of existing thing" usage: renameit.py [-h] [-v] old_name new_name junk.py: error: the following arguments are required: new_name
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question Two arguments in input function Alfredd 4 735 Nov-09-2025, 12:56 AM
Last Post: Pedroski55
  function arguments Curbie 2 1,003 Apr-30-2025, 05:23 PM
Last Post: Curbie
  Why doesn't calling a parent constructor work with arbitrary keyword arguments? PurposefulCoder 4 2,756 Jun-24-2023, 02:14 PM
Last Post: deanhystad
  Calling a function (which accesses a library) from another file mouse9095 4 6,261 Jun-07-2023, 08:55 PM
Last Post: deanhystad
Sad Iterate randint() multiple times when calling a function Jake123 2 4,142 Feb-15-2022, 10:56 PM
Last Post: deanhystad
  Calling a class from a function jc4d 5 3,930 Dec-17-2021, 09:04 PM
Last Post: ndc85430
  'namespace' shorthand for function arguments? shadowphile 5 4,411 Aug-11-2021, 09:02 PM
Last Post: shadowphile
  Checking the number of arguments a function takes Chirumer 3 3,603 Jul-06-2021, 04:56 PM
Last Post: Chirumer
  [Solved] TypeError when calling function Laplace12 2 4,536 Jun-16-2021, 02:46 PM
Last Post: Laplace12
  Possible to dynamically pass arguments to a function? grimm1111 2 3,577 Feb-21-2021, 05:57 AM
Last Post: deanhystad

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020
This forum uses Lukasz Tkacz MyBB addons.
Forum use Krzysztof "Supryk" Supryczynski addons.