Python Properties and C# 3.0 Language FeaturesNew Ways of Doing Properties, LINQ and Other Stuff![]()
Contents
IntroductionThis article is inspired by a talk I went to at TechEd Barcelona about new language features in C# 3.0: perhaps there is something that Python can learn from then! One of the features is an improvement to the way trivial properties are declared in C#. The C# syntax for declaring properties is cleaner than Python, despite recent changes implemented by Guido. This article starts by looking at property syntax in Python (old and new) and C#, including a new way that I have implemented inspired by the C# syntax. This uses metaclasses and descriptors (under the hood), so it is pretty fun geek stuff even if you don't use it! The middle part of the article is a look at some of the other new language features in C# 3, and which of them Python might be able to learn from. It finishes with a look at the major new language feature (LINQ) and whether it is possible to add this to Python. Properties in Python and CSharpThe current way of declaring properties in Python is a little awkward: class Class(object): def __init__(self): self.__attribute = None def __getattribute(self): return self.__attribute def __setattribute(self, value): self.__attribute = value attribute = property( fget = __getattribute, fset = __setattribute ) Of course if you want a read-only property, you can use the property decorator which is much nicer: class Class(object): def __init__(self): self._something = None @property def something(self): return self._something Guido has just checked in an improvement to the way you create properties. This will appear in Python 2.6 and 3.0, and lets you use decorators to declare the setter and deleter methods as well: class Something(object): def __init__(self): self._something = None @property def something(self): return self._something @something.setter def something(self, value): self._something = value @something.deleter def something(self): del self._something This is a great improvement, but it still isn't as clean as the property syntax in C#:
class Something {
private Object _something;
public Object something {
get { return _something; }
set { _something = value; }
}
}
Excluding the deleter (which C# doesn't allow) (and ignoring whitespace and curly brace lines), C# is five lines and Python nine lines. Using a metaclass and descriptors, we can get something similar to the C# syntax in Python. Python Properties Inspired by C# SyntaxNote I've also implemented another way of automatically declaring properties in Python; by declaring methods that begin with 'get_', 'set_' or 'del_': Using a metaclasses and the descriptor protocol, we can get the equivalent of the C# syntax in Python. It isn't many lines shorter, but perhaps more readable than the current solution (and is available today): class Something(object): def __init__(self, x): self.x = x class something(Property): def get(owner): return owner.x def set(owner, value): owner.x = value s = Something(3) print s.something s.something = 4 print s.something The property is the inner class, with get and set methods. The magic behind the scenes is the Property class and its metaclass Meta: from types import FunctionType, MethodType class Meta(type): def __new__(meta, classname, bases, classDict): for name, entry in classDict.items(): if isinstance(entry, (FunctionType, MethodType)): classDict[name] = staticmethod(entry) return type.__new__(meta, classname, bases, classDict) def __get__(self, instance, owner): return self.get(instance) def __set__(self, instance, value): return self.set(instance, value) class Property(object): __metaclass__ = Meta It's a bit magic, but fun. Your properties, implemented as inner classes, must inherit from Property. This has a metaclass, so that all methods get turned into static methods. Because the metaclass implements __get__ and __set__, they are used when the property class is fetched on an instance. This descriptor magic makes sure that getting or setting the property does the right thing - including giving you access to the instance that contains it. The reason that I started thinking about this is that 'Automatic property declaration' is one of the new features of C# 3.0. New Language Features in C# 3.0C# 3.0 is part of the .NET 3.5 and introduces new language features. A lot of the new language features are actually to support the major new feature of C# 3.0, which is LINQ. Some of these features are just C# playing catchup with dynamic languages like Python. Catchup Language Features
New and (Possibly) Innovative FeaturesThere are also some language features that are new and interesting. Some of them wouldn't be out of place in Python, but might be very hard to implement.
Implementing LINQ for PythonIf Python was to add some LINQ like support within list comprehensions (which LINQ already closely resembles) then it would need to generate an expression tree for the filter part of a list comprehension. The data provider would then need to be able to decompose the expression tree into a query. One way to achieve this would be to keep the AST around after initial parsing. Let me give you an idea of how it might work for the following list comprehension: customers = DataProvider() data = [(c.Name, c.Value) for c in customers if c.City == "London"] The DataProvider would provide a __query__ method that takes an AST. For every list comprehension the compiler would have to keep the AST for the expression if c.City == London. Python would then check if customers has __query__, if it does then it will be called with the AST. The AST could have also have the compiled version of the expression (needed for ordinary list comprehension). This would effectively be a lambda taking c as an argument. Of course this is only interesting if data providers are implemented that could decompose the AST into optimised queries (which is exactly what Microsoft has done with LINQ). The complexity of implementing this, and possible performance costs in list comprehensions, means that it is unlikely to happen in Python. Still, LINQ is a worthy way of providing a uniform way of querying data and making queries a first class part of the language. A related question is how can we get this into IronPython. Adding it would mean adding new syntax to Python, which the community (me included) would be very dubious about. Perhaps a compromise similar to the way .NET methods are enabled / disabled on builtin types. Until you do import clr (or import System) the .NET methods are unavailable. A __future__ import would be one way of supporting this - perhaps by agreement with the CPython developers that the corresponding flag will never be used by CPython. I've recently been wondering about a way of experimenting with adding language features like this. The ANTLR parser has a Python grammar. If you could write an ANTLR AST to Python AST transform, then you could extend the ANTLR Python grammar and still transform to a valid Python AST. Obviously you could only add syntactic sugar to the language, but its surprising how much you can achieve with a bit of sugar! For example what I'd really like to experiment with is adding syntax for code blocks. The transform phase could transform code block syntax into functions with a compiler assigned name. It would be interesting to see how useful code blocks are in practise. For buying techie books, science fiction, computer hardware or the latest gadgets: visit The Voidspace Amazon Store. If you're looking for a new techie job, try the Voidspace Tech Job Board. This is part of the Hidden Network of technology and programming jobs.
Last edited Fri Feb 15 13:42:08 2008. Counter... |
|
|
Blogads
Follow me on: Tech Jobs |