IronPython calls TryGetMember instead of TryInvokeMember

I am trying to pass a dynamic Ironpython object, but it looks like Ironpython is not calling TryInvokeMember. Instead, it calls TryGetMember and gives an error that cannot cause the result.

I tried this with IronPython 2.7 and 2.6.10920

ExampleCode:

DynamicObject:

class ExampleDynamicObject: DynamicObject { public override bool TryGetMember(GetMemberBinder binder, out object result) { result = "TryGetMember"; return true; } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = "TryInvokeMember"; return true; } } 

call mathode

 static void Main(string[] args) { dynamic example = new ExampleDynamicObject(); var program = @"test = example.Call2(2)"; var engine = Python.CreateEngine(); var scope = engine.CreateScope(); scope.SetVariable("example", example); var source = engine.CreateScriptSourceFromString(program, SourceCodeKind.Statements); source.Execute(scope); Console.ReadKey(); } 

This calls the TryGetMember method and then throws the Microsoft.Scripting.ArgumentTypeException command "str cannot be called"

This throws when the code has something like "test" (1)

So, it seems that Python does not understand that this is a function call, but simply calls a property.

But when I try to call it from C #

  Console.WriteLine(example.Call); Console.WriteLine("----------------------------"); Console.WriteLine(example.Call(1)); 

This will work:

 TryGetMember ------------------- TryInvokeMember 

Does anyone have a suggestion to fix this?

Solution: (edit: namedMethodeName should be a list, otherwise nested methods will not work)

So thanks to Jeff.

When I create Dynamic as follows:

 List<string> calledMethodeNames = new List<string>(); public override bool TryGetMember(GetMemberBinder binder, out object result) { calledMethodeNames.Add(binder.Name); result = this; return true; } public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { //calledMethodeNames last Element has stored the Name of the called methode (remeber to remove it) result = "TryInvoke"; return true; } 

everything is working fine.

The hint is to return the object as a member than the object being called, and python calls TryInvoke (not TryInvokeMember)

But TryInvoke ist is called because after the return of the object, the object itself is called. So InvokeBinder does not know the name of the called method. Therefore, I store it in a variable.

+4
source share
2 answers

This is the expected behavior. IronPython uses TryGetMember followed by TryInvoke , since Python does not have the concept of invoking an element: Python method calls are always an attribute TryInvoke and then a call.

The error you get is that you set result to a string (type str ) and the strings are not callable. You need to set result to another dynamic object that implements TryInvoke or a delegate.

+2
source

Based on the Python exception (str is not called), it looks like IronPython first calls TryGetMember , and since this function returns true, it will use this object.

TryGetMember/TryInvokeMember should return true only if they succeed. For example, this means that TryGetMember should return true if and only if there is actually a member that matches the binder parameter.

Update: In C #, Call(2) always a method call (I can't think of anything else that maybe let me know if I'm wrong), so the C # compiler will use TryInvokeMethod . However, in Python, any object can be called if it has the __call__ method, so Call(2) can mean executing the Call method or get a Call member and execute __call__ on it.

0
source

Source: https://habr.com/ru/post/1486220/


All Articles