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: m.scha...@codesys.com | 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 Ironpython-users@python.org https://mail.python.org/mailman/listinfo/ironpython-users