Hi,
As far as I can see, the "in" operator should return true if any object in the
enumerable is "equal" to the object given as reference:
IronPython 2.7.5 (2.7.5.0) on .NET 4.0.30319.34209 (32-bit)
Type "help", "copyright", "credits" or "license" for more information.
>>> t = (1,2)
>>> o = (t, 3, "4", 1024)
>>> 1024 in o
True
>>> "4" in o
True
>>> (1,2) in o
True
>>> t in o
True
>>> a = 2**100
>>> b = 2**100
>>> a in (b,)
True
>>> a is b
False
>>> import System
>>> g = System.Guid.NewGuid()
>>> h = System.Guid(g.ToString())
>>> g == h
True
>>> g is h
False
>>> g in (h,)
True
However, it looks like this is not working correctly with
IDynamicMetaObjectProvider implementations.
I attached an example which is a stripped down case of some much more complex
real world code[1]. In that case, the assertion in the last line fails although
a equals b.
# a and b are provided by the host written in C#
assert a == b, 'a equals b'
assert not a is b, 'a is not b'
assert a in (a,), 'a is in (a,)'
assert a in (b,), 'a is in (b,)' # this one fails...
As far as I can see via breakpoints, the Equals methods of the objects are
never actually called, except on the first assertion with the == operator.
[1] In the real world code, arbitrary plugins may provide extensions to
extendable objects from other plugins, to dynamically (at run-time) add methods
and properties to those instances.
Best regards
Markus Schaber
CODESYS(r) a trademark of 3S-Smart Software Solutions GmbH
Inspiring Automation Solutions
3S-Smart Software Solutions GmbH
Dipl.-Inf. Markus Schaber | Product Development Core Technology
Memminger Str. 151 | 87439 Kempten | Germany
Tel. +49-831-54031-979 | Fax +49-831-54031-50
E-Mail: [email protected] | Web: http://www.codesys.com | CODESYS store:
http://store.codesys.com
CODESYS forum: http://forum.codesys.com
Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade
register: Kempten HRB 6186 | Tax ID No.: DE 167014915
This e-mail may contain confidential and/or privileged information. If you are
not the intended recipient (or have received
this e-mail in error) please notify the sender immediately and destroy this
e-mail. Any unauthorised copying, disclosure
or distribution of the material in this e-mail is strictly forbidden.
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
public class ScriptExecutor
{
private const string SRC = @"
assert a.bar();
assert a.extension1() == 0;
assert a == b, 'a equals b'
assert not a is b, 'a is not b'
assert a in (a,), 'a is in (a,)'
assert a in (b,), 'a is in (b,)'
";
private static void Main()
{
try
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource scriptSource =
engine.CreateScriptSourceFromString(SRC, "test.py");
engine.Runtime.LoadAssembly(typeof(ScriptExecutor).Assembly);
ScriptScope scope = engine.CreateScope();
scope.SetVariable("a", new Foo().Extender);
scope.SetVariable("b", new Foo().Extender);
scriptSource.Execute(scope);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.WriteLine("Script Finished");
Console.ReadLine();
}
}
}
public interface IFoo : IBaseObject<IFoo>
{
bool bar();
}
public class Foo : IFoo
{
public Foo()
{
this.Extender = ExtendedObject<IFoo>.Create(this);
}
public override bool Equals(object obj)
{
return true;
}
public bool Equals(Foo other)
{
return true;
}
public override int GetHashCode()
{
return 0;
}
public bool bar()
{
return true;
}
public IExtendedObject<IFoo> Extender
{
get;
private set;
}
public bool Equals(IFoo other)
{
return true;
}
public bool Equals(IExtendedObject<IFoo> other)
{
return true;
}
}
internal class ExtendedObject<T> : IDynamicMetaObjectProvider,
IExtendedObject<T>
where T : IBaseObject<T>
{
private readonly T BASE_OBJECT;
internal readonly IList<object> EXTENSIONS = new List<object>();
private ExtendedObject(T baseObject)
{
this.BASE_OBJECT = baseObject;
}
#region IDynamicMetaObjectProvider Members
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new ScriptMetaObject<T>(parameter,
BindingRestrictions.Empty, this);
}
#endregion
#region IExtendedObject<T> Members
public T BaseObject
{
get { return BASE_OBJECT; }
}
public IEnumerable<object> Extensions
{
get
{
for (int i = 1; i < EXTENSIONS.Count - 1; i += 1)
{
yield return EXTENSIONS[i];
}
}
}
#endregion
// TODO: Cacheing of ExtendableTypes...
internal static ExtendedObject<T> Create(T baseObject)
{
ExtendedObject<T> result = new ExtendedObject<T>(baseObject);
// We put the base object into search path s_first so that
exceptions are mapped to the
// correct type.
result.EXTENSIONS.Add(baseObject);
// In the real code, a bunch of extensions is fetched from the
plugin manager.
result.EXTENSIONS.Add(new Extension1());
// We also put the base object into the search past s_last so
that the base object overrides
// extension objects.
result.EXTENSIONS.Add(baseObject);
return result;
}
public override string ToString()
{
return BASE_OBJECT.ToString();
}
public override bool Equals(object obj)
{
return BASE_OBJECT.Equals(obj);
}
public override int GetHashCode()
{
return BASE_OBJECT.GetHashCode();
}
}
internal static class MyDynamicObjectOps<T>
where T : IBaseObject<T>
{
public static object GetPlugin(object myDo, int index)
{
return ((ExtendedObject<T>)myDo).EXTENSIONS[index];
}
internal static MethodInfo GetPluginMethod =
typeof(MyDynamicObjectOps<T>).GetMethod("GetPlugin");
}
internal class ScriptMetaObject<T> : DynamicMetaObject
where T : IBaseObject<T>
{
public ScriptMetaObject(Expression parameter, BindingRestrictions
restrictions, ExtendedObject<T> value)
: base(parameter, restrictions, value)
{
}
public new ExtendedObject<T> Value
{
get
{
return (ExtendedObject<T>)base.Value;
}
}
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder
binder, DynamicMetaObject[] args)
{
DynamicMetaObject boundMember = null;
for (int i = 0; i < Value.EXTENSIONS.Count; i++)
{
DynamicMetaObject pluginDo = new DynamicMetaObject(
Expression.Call(
MyDynamicObjectOps<T>.GetPluginMethod,
Expression,
Expression.Constant(i)
),
BindingRestrictions.GetInstanceRestriction(this.Expression, Value),
Value.EXTENSIONS[i]
);
boundMember = binder.FallbackInvokeMember(pluginDo,
args, boundMember);
}
return boundMember;
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder,
DynamicMetaObject value)
{
DynamicMetaObject boundMember = null;
for (int i = 0; i < Value.EXTENSIONS.Count; i++)
{
DynamicMetaObject pluginDo = new DynamicMetaObject(
Expression.Call(
MyDynamicObjectOps<T>.GetPluginMethod,
Expression,
Expression.Constant(i)
),
BindingRestrictions.GetInstanceRestriction(this.Expression, Value),
Value.EXTENSIONS[i]);
boundMember = binder.FallbackSetMember(pluginDo, value,
boundMember);
}
return boundMember;
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
DynamicMetaObject boundMember = null;
for (int i = 0; i < Value.EXTENSIONS.Count; i++)
{
DynamicMetaObject pluginDo = new
DynamicMetaObject(Expression.Call(
MyDynamicObjectOps<T>.GetPluginMethod,
Expression,
Expression.Constant(i)
),
BindingRestrictions.GetInstanceRestriction(this.Expression, Value),
Value.EXTENSIONS[i]);
boundMember = binder.FallbackGetMember(pluginDo,
boundMember);
}
return boundMember;
}
public override DynamicMetaObject
BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
// Currently only supported for equality (python == operator)
equality, we bind to the base object only.
DynamicMetaObject baseDo = new
DynamicMetaObject(Expression.Call(
MyDynamicObjectOps<T>.GetPluginMethod,
Expression,
Expression.Constant(0)
),
BindingRestrictions.GetInstanceRestriction(this.Expression, Value),
Value.EXTENSIONS[0]);
return binder.FallbackBinaryOperation(baseDo, arg, null);
}
}
public interface IExtendedObject<T>
where T : IBaseObject<T>
{
T BaseObject { get; }
IEnumerable<Object> Extensions { get; }
}
public interface IBaseObject<T> : IEquatable<T>, IEquatable<IExtendedObject<T>>
where T : IBaseObject<T>
{
IExtendedObject<T> Extender { get; }
}
public class Extension1
{
public int extension1() { return 0; }
}
_______________________________________________
Ironpython-users mailing list
[email protected]
https://mail.python.org/mailman/listinfo/ironpython-users