Outpost Universe Forums

Off Topic => Computers & Programming General => Topic started by: lordpalandus on July 17, 2018, 01:12:00 AM

Title: Can someone explain to me why this works (Python)
Post by: lordpalandus on July 17, 2018, 01:12:00 AM
So, while working on my Python code, I ran across something interesting, which I will elaborate below:

Code: [Select]
def Sum_Up():
  x = 2
  y = 4
  total = x + y
  return total

#If pressed: Shift + 1

call_function = Sum_Up
printf call_function()

This then causes the function call Sum_Up() to be called and executes the code and prints 6 to the base console (or Shell I believe it is called).

My question is Why does this work? When call_function is initialized to Sum_Up, it appears to be not a function call, yet when you add () to the end of it, it becomes a function call. Could someone explain why this works? I know that if you assign a function call to some other name and call it, then it calls that code. ie

call_function = Sum_Up()

But I do not understand why/what Sum_Up is when it lacks the (), or why it suddenly creates a legitimate function call when () is added to call_function.

Thanks in advance!
Title: Re: Can someone explain to me why this works (Python)
Post by: leeor_net on July 17, 2018, 01:14:47 PM
Without knowing the semantics and internals of Python, basically what you're doing is creating a function object. Many languages allow (or require) '()' as an operator similar to '+', '+=', '--', etc.

With a [very] brief glimpse over the documentation by storing your function in a variable you're basically creating a 'callable object' (aka function object, functor, etc.) which is where 'operator()' comes in.

FURTHER READING: https://en.wikibooks.org/wiki/Python_Programming/Functions
Title: Re: Can someone explain to me why this works (Python)
Post by: lordpalandus on July 17, 2018, 09:32:07 PM
First time I've heard the term, "function object".

So... then what is "Sum_Up" when it doesn't have the () attached to it? I know that once it has the () it becomes a function, but what is it before the () is attached?

Also, can you store a member function in a similar manner;

ie deal_damage = player.fighter.take_damage
deal_damage(50)  #Would this call the member function take_damage, for the player?
Title: Re: Can someone explain to me why this works (Python)
Post by: Crow! on July 17, 2018, 10:35:49 PM
Yeah, something to that effect should work fine in python.


For a more practical example of why you'd want to treat functions themselves as variables, consider "events", which are a common way for GUIs to work.  If one object (say, a text box) wants to do something once some other object (say, a button) has some event occur (it gets clicked), you generally add a function (called an event handler) that belongs to the first object to a list of functions on the second object that will all get executed when the event happens.

As for the name of a function lying around being a function, python calls those "callable objects".
Title: Re: Can someone explain to me why this works (Python)
Post by: leeor_net on July 19, 2018, 09:16:43 AM
As for the name of a function lying around being a function, python calls those "callable objects".

This right here.

Callable Object == Function Object;
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on July 22, 2018, 04:18:02 AM
I'm not sure of the specific terminology related to Python, but this is akin to function pointers in C/C++.

Sum_Up is a function. It represents the code itself, not the execution of it. Think of it like the actual source code listing, or the compiled machine code equivalent of it.
Sum_Up() is a call to a function. It executes the code in the function.

call_function is then just a variable which holds a function (or rather a pointer to a function).
call_function() is a call to the pointed to function.
Title: Re: Can someone explain to me why this works (Python)
Post by: leeor_net on July 22, 2018, 09:28:47 AM
I imagine that's how it's implemented in C/C++ (not sure what Python is actually implemented in) but it really screams functor/callable object semantics in C++ (e.g., bind that works on any callable object). So eh, I dunno. Python developers could define it better but it makes perfect sense to me.
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on July 22, 2018, 11:57:34 AM
Hmm, in JavaScript there is bind, which can set the this pointer for the called function (and fix other parameters too). That can allow you to call member functions outside the context of the host object, and still have it work.

I think there is a minor distinction between a function pointer and a functor. Since a functor is an object, it can have mutable state associated with it. That state might be set by the constructor, and it might be updated on each call. Hence you can get different results from the functor for the same parameters, even if the function itself is pure (doesn't access global/static memory, nor call any functions that do, and in particular isn't capable of input/output operations). A function pointer can't do that.

In terms of syntax and operator() overloading, they appear identical. You're calling something.
Title: Re: Can someone explain to me why this works (Python)
Post by: lordpalandus on July 22, 2018, 01:57:23 PM
I believe the creator of Python, has stated that the Python Interpreter is written in C. Maybe also some Pascal code.
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on July 24, 2018, 01:34:53 AM
I suppose there is one easy way to answer this. The python programming language (CPython) (https://github.com/python/cpython) is up on GitHub.

Checking the GitHub statistics, the repository contains:
61% Python
32.5% C
3.6% Objective-C
1.4% C++
0.4% M4
0.4% HTML
0.7% other

Based on the percentages, I assume that means there is a lot of example code, or a standard library written in Python, with the main interpreter written in C, and bindings for Objective-C and C++. The other stuff is likely related to the build system and documentation.

Keep in mind though, this is just one interpreter for the Python language. There are other interpreters, such as IronPython (.NET) (https://github.com/IronLanguages), Jython (Java) (https://github.com/jythontools/jython), PyPy (Python) (https://github.com/mozillazg/pypy), and of course many others. It is more correct to say that a specific compiler or interpreter for Python is written in some programming language, rather than say the language itself is written in that. The language is just a specification. It's the implementation that is dependent on a language.
Title: Re: Can someone explain to me why this works (Python)
Post by: Crow! on July 27, 2018, 07:51:24 AM
You can hook up precompiled c code to work within a python script to do certain tasks faster than the interpreter could do it.  Some of those percentages you see there might be implementations for that.
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on August 04, 2018, 11:47:00 PM
True, though in the case of CPython I found a note that it is actually implemented in C. Hence the name CPython.  ;D
Title: Re: Can someone explain to me why this works (Python)
Post by: Angellus Mortis on October 03, 2018, 12:16:10 PM
Hey, a language I know a lot about. Yeah, the most common implementation of Python is CPython, but there is also PyPi (a stackless implementation of CPython), Jython (Java implementation), IronPython (.NET implementation), and pypy.js (implementation of PyPy using Javascript using asm.js). I am actually personally hoping the guys being pypy.js convert it to use WebAssembly instead of asm.js. If they solved the performance issues in pypy.js, you could actually build a full Website using Python and no Javascript. That is the whole idea behind WebAssembly is to be kind of like the JVM or .NET Runtime, but in a Web browser so you can make sites without Javascript.

Anyways, to the original question, yeah Python, as well as most "scripting" languages actually have everything as variables, including functions.

Code: [Select]
>>> def test():
...    return 1
...
>>> test
<function test at 0x7f9f76e6ebf8>
>>> test()
1
>>> type(test)
<class 'function'>
>>>

Functions can be manipulated just like any other variable and allow them to do a lot of really interesting things actually. Most notable are decorators. Decorators let you do all kind of cool and weird stuff. For example, C# has an interesting idea of how getters/setters function on classes via something called "Properties"

Code: [Select]
class TimePeriod
{
   private double seconds;

   public double Hours
   {
       get { return seconds / 3600; }
       set {
          if (value < 0 || value > 24)
             throw new ArgumentOutOfRangeException(
                   $"{nameof(value)} must be between 0 and 24.");

          seconds = value * 3600;
       }
   }
}

Python has something similar via the "property" decorator.

Code: [Select]
>>> class A():
...     _test = 10
...     @property
...     def test(self):
...         return self._test
...     @test.setter
...     def test(self, value):
...         self._test = value
...
>>> a = A()
>>> a.test
10
>>> a._test
10
>>> a.test = 20
>>> a.test
20
>>> a._test
20
>>>

Also, as you can see from the above example, Python does not actually have access modifiers like C++/Java/C# does. Everything is "technically" public, but generally anything that is prefixed with _ is considered "private" in terms of the implementation API. If you make a member start with _, you are basically saying, "In a future version of this application, I can remove this member and it will be considered a non-breaking change".


Title: Re: Can someone explain to me why this works (Python)
Post by: leeor_net on October 03, 2018, 09:31:59 PM
Eeesh, it's just as bad as I remember. C# makes is so much easier to read/understand.
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on October 03, 2018, 10:00:37 PM
My dislike of underscore knows no bounds.

I also found the explicit placement of self in member function parameter lists to be a bit off putting. I can understand why it's there, particularly with how member functions in C++ would need to be written when translated into C. I just never much liked it as part of the language syntax.
Title: Re: Can someone explain to me why this works (Python)
Post by: Angellus Mortis on October 04, 2018, 05:25:54 AM
My dislike of underscore knows no bounds.

Eh. You get use to it. I had a co-worker in college that always used snake_case and I was just so use to using camelCase, I could not stand it. Then I started using Python a lot more and I started to like it. Python is design a lot for readability and I found snake_case a lot easier to read once you get use to it. Python does still use PascalCase for class names though.
Title: Re: Can someone explain to me why this works (Python)
Post by: leeor_net on October 04, 2018, 08:28:36 AM
I prepend underscore only to internal only member functions of classes... it's a stylistic choice and hardly set in stone. It's also a somewhat recent choice.

As for naming conventions, PascalCase for classes, camelCase for functions, snake_case_only_for_really_long_function_names_though_this_is_a_good_indication_that_im_doing_it_wrong.
Title: Re: Can someone explain to me why this works (Python)
Post by: Hooman on October 04, 2018, 10:02:06 AM
I find typing excessive number of snake_case identifiers leaves my wrists sore by the end of the day. Might have been related to years of bad self taught typing habits. Though I suspect most programmers are similar there. There was a time when it was getting really bad with lots of ALL_UPPERCASE_SNAKE_CASE_MACRO_NAMES, and I eventually resorted to using caps lock to type identifier names. That's probably about the only time in my life that I'd bothered to seriously use caps lock.

I have since put in some effort to learn how to type the "proper" way, where you use shift from the opposite hand used to type the letter. It helps. I still find it slower and more frustrating to type snake_case though.



I much prefer no prefixes on variables. Syntax highlighting will often tell you the difference between local and member variables anyway. If you really need to be clear, you can use a this prefix. Actually, in template member functions, you're forced to use this when accessing a base class member, since otherwise dependent name lookup will fail. For an interesting read, see Why do I have to access template base class members through the this pointer? (https://stackoverflow.com/questions/4643074/why-do-i-have-to-access-template-base-class-members-through-the-this-pointer/4643295)