Author Topic: Can someone explain to me why this works (Python)  (Read 7683 times)

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Can someone explain to me why this works (Python)
« on: July 17, 2018, 03: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!
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2352
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Can someone explain to me why this works (Python)
« Reply #1 on: July 17, 2018, 03: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
« Last Edit: July 17, 2018, 03:17:52 PM by leeor_net »

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Can someone explain to me why this works (Python)
« Reply #2 on: July 17, 2018, 11: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?
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline Crow!

  • Jr. Member
  • **
  • Posts: 74
Re: Can someone explain to me why this works (Python)
« Reply #3 on: July 18, 2018, 12:35:49 AM »
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".
Speedruns, my FFIV game randomizer, and more can be found at my twitch page:
https://twitch.tv/iicrowii

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2352
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Can someone explain to me why this works (Python)
« Reply #4 on: July 19, 2018, 11: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;

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #5 on: July 22, 2018, 06: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.
« Last Edit: July 22, 2018, 06:19:43 AM by Hooman »

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2352
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Can someone explain to me why this works (Python)
« Reply #6 on: July 22, 2018, 11: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.

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #7 on: July 22, 2018, 01:57:34 PM »
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.

Offline lordpalandus

  • Banned
  • Hero Member
  • *****
  • Posts: 825
Re: Can someone explain to me why this works (Python)
« Reply #8 on: July 22, 2018, 03:57:23 PM »
I believe the creator of Python, has stated that the Python Interpreter is written in C. Maybe also some Pascal code.
Currently working on Cataclysm of Chaos, Remade.
Link to OPU page = http://forum.outpost2.net/index.php/topic,6073.0.html

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #9 on: July 24, 2018, 03:34:53 AM »
I suppose there is one easy way to answer this. The python programming language (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), Jython (Java), PyPy (Python), 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.

Offline Crow!

  • Jr. Member
  • **
  • Posts: 74
Re: Can someone explain to me why this works (Python)
« Reply #10 on: July 27, 2018, 09: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.
Speedruns, my FFIV game randomizer, and more can be found at my twitch page:
https://twitch.tv/iicrowii

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #11 on: August 05, 2018, 01:47:00 AM »
True, though in the case of CPython I found a note that it is actually implemented in C. Hence the name CPython.  ;D

Offline Angellus Mortis

  • Full Member
  • ***
  • Posts: 138
Re: Can someone explain to me why this works (Python)
« Reply #12 on: October 03, 2018, 02: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".



Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2352
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Can someone explain to me why this works (Python)
« Reply #13 on: October 03, 2018, 11:31:59 PM »
Eeesh, it's just as bad as I remember. C# makes is so much easier to read/understand.

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #14 on: October 04, 2018, 12:00:37 AM »
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.

Offline Angellus Mortis

  • Full Member
  • ***
  • Posts: 138
Re: Can someone explain to me why this works (Python)
« Reply #15 on: October 04, 2018, 07: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.

Offline leeor_net

  • Administrator
  • Hero Member
  • *****
  • Posts: 2352
  • OPHD Lead Developer
    • LairWorks Entertainment
Re: Can someone explain to me why this works (Python)
« Reply #16 on: October 04, 2018, 10: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.

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Re: Can someone explain to me why this works (Python)
« Reply #17 on: October 04, 2018, 12:02:06 PM »
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?