question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

__call__ special method not working

See original GitHub issue

Context

class tester:
  def __init__(self):
    print("init")

  def go(self):
    print("go")

# specal method:
  def __call__(self, arg):
    print("call:", arg)

test = tester()
test.go()
test.__call__(1)
test(2)                   # <<<< invoke the special method; use object as functor

Expected and Desired Behavior (ordinary python)

init
go
call: 1
call: 2

This works just fine in python2.7, python3.4, ipython2.7, and ipthon3.

Observed Behavior (RS)

init
go
call: 1
[stdin]:152
test(2);
^
TypeError: object is not a function
    at [stdin]:152:1
    at Object.exports.runInThisContext (vm.js:74:17)
    at Object.<anonymous> ([stdin]-wrapper:6:22)
    at Module._compile (module.js:460:26)
    at evalScript (node.js:431:25)
    at Socket.<anonymous> (node.js:164:11)
    at Socket.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)

Workaround

Just invoke test.__call__(...) instead of test(...)

Discussion

There are ways of making functors in javascript, using closures … but I reckon it is both easier (at compile time) and more efficient (at run time) if the compiler just catches the pythonic functor expression and maps it to the __call__ special method.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:20 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
kovidgoyalcommented, Sep 20, 2015

To summarize, the problems with using function objects to implement __call__ are:

  1. Changing object prototype dynamically is not available in all JS runtimes. This could potentially be worked around by manually copying properties, but IMO, that is just a slow, ugly mess.

  2. The list of properties and type of the object will be changed by simply adding a __call__ method to the object. This is highly unexpected. See code below:

o = Object.create(null)
f = (function () {})
typeof o == 'object'
typeof f == 'function'
typeof o.apply == 'undefined'
typeof f.apply == 'function'
  1. No evidence beyond vague hand-waving was presented to counter the claim on MDN that dynamically changing the prototype will slow down attribute access on the resulting object

  2. I am willing to ignore this – __call__ simply wont work for runtimes without this facility.

  3. This is a problem. In particular the type() of the resulting object changing is highly unexpected. Any code based on type inspection that expects an object will break.

  4. This is a problem, unless someone can present some actual evidence that it is not.

IMO the call operator () suffers from the same problem as all other operators in RS – namely that it cannot be overloaded. Any solution for this problem should be a general solution for the operator overloading problem as a whole. I am still inclined towards simply enabling all operator overloading on a per-module basis. This allows the user to choose which is more important to him – performance or python compatibility, on a fairly granular level.

The issue with that is the different behavior of indexOf() when used with non-primitive types. I am inclining towards ignoring that as the cost of doing business. The RS provided index() method can be made to work (it will check if the passed in argument has an __eq__ method, and if it does it will loop through the array checking with __eq__ and otherwise fallback to indexOf). This should cover 99% of the use cases. It is still not fully compatible with python since in theory, a custom class could has an __eq__ method that returns true for primitive types, but that should be pretty rare.

There is a similar issue with the python-like dict and set types. Currently in my fork I have an implementation for them that use the JS Map and Set types where available. The problem with that is that they do not use __hash__ and __eq__. This can be worked around by implementing a hashmap in pure JS that will use those methods when defined, otherwise falling back to toString().

0reactions
artyprogcommented, Sep 19, 2015

If only I have your knowledges I would attempt to unify our competences to accomplish great things for the community… Life is very short, don’t waste it…

2015-09-19 9:08 GMT+02:00 Kovid Goyal notifications@github.com:

ROFL how did I just know that was coming.

— Reply to this email directly or view it on GitHub https://github.com/atsepkov/RapydScript/issues/98#issuecomment-141631896 .

Read more comments on GitHub >

github_iconTop Results From Across the Web

Python __call__ special method practical example
Here we use a simple class with a __call__ method to calculate factorials (through a callable object) instead of a factorial function that...
Read more >
Special Method Names - Dive Into Python 3
Using special methods, your classes can act like sets, like dictionaries, ... If an instance x defines an attribute color , x.color will...
Read more >
Special Methods - Python Like You Mean It
Special Methods . In this section, we will learn about a variety of instance methods that are reserved by Python, which affect an...
Read more >
constructor - JavaScript - MDN Web Docs - Mozilla
The constructor method is a special method of a class for creating and initializing an object instance of that class.
Read more >
3. Data model — Python 3.11.1 documentation
Special writable attributes: f_trace , if not None , is a function called for various events during code execution (this is used by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found