Defining function without the brackets?

2020-02-01 03:46发布

问题:

I understand that my question might sound stupid, and that there might be something in the language definition that explicitly prohibits this notion, but since I don't know about this prohibition, I was wondering whether someone could shed some light on it. In short, I would like to define a python function that I could call from the python shell, but I would like to avoid the brackets. There are cases when a function does not require an argument, and then the bracket only seems to indicate that we are dealing with a function. Such an example would be, if one wants to print the current working directory. I can define a function as

def pwd():
    print os.getcwd()

and then I can call it from the shell as

pwd()

But what if I would like to have a function that I can call as

pwd

Is this possible at all?

回答1:

You're going to get some syntax in there somewhere. You could try something like:

import os
class Shell(object):
    @property
    def pwd(self):
        print os.getcwd()

And then in your interpreter, run:

>>> s = Shell()
>>> s.pwd
/tmp


回答2:

You can't do this without modifying the language or the shell.

If you want to use Python as a shell, you should really try IPython, it allows you to define macros that you can use without typing as many keys. It also lets you do !pwd, you can assign this to a variable as well x = !pwd. It even lets you call single argument functions by writing f x instead of f(x).

BTW Haskell is a language that uses spaces for list of arguments, i.e: f(1,2,3) in Python would be f 1 2 3 in Haskell, and in the shell any IO action can be executed by just typing action.

I forgot there's also a hack you can do:

class Pwd(object):
    def __repr__(self):
        # do pwd command
        # return result in string form
pwd = Pwd()

Now when you type pwd in the shell, it will call __repr__ to get a string representation of the object. Unfortunately, you're restricted to returning a string (as opposed to say, a list of strings representing the files/folders in the current directory, if you were implementing ls) because the python language forces this.



回答3:

It is not possible. A bare reference to a variable (e.g. pwd) never does anything special, it just retrieves the reference stored in that variable. If that variable was bound to a function, this reference is a reference to a function, but either way it's just a reference and nothing more. To actually call anything, you have to use the syntax for function calls - expression '(' arglist ')'.

Now, this doesn't apply to properties of objects (i.e. of anything), as getting a member is technically already a function call, and can be overridden. There are actually numerous ways one can influence what obj.member evaluates to, the most important ones being __getattr__, __getattribute__, and __get__ in a descriptor. For the latter two, there are equivalents to setting attributes (yes, that's a distinct operation). All of these are documented in the language reference.

It'd still a pretty bad idea to use this to implicitly call a procedure (as opposed to getters), as it's counter-intuitive, makes the code less obvious and has absolutely no benefit aside from saving you two parens. It would also disallow getting a reference to the function, which makes functional and functional-inspired programming with it very inconvenient (you could use lambda: obj.pwd, but that's even less obvious and uglier).