Quoting Paul Rubin <"http://phr.cx"@NOSPAM.invalid>:
> Luis Zarrabeitia <ky...@uh.cu> writes: > > > Luis Zarrabeitia <ky...@uh.cu> writes: > > class ImmutableType(type): ... > > Thanks for posting this, I haven't replied because I bookmarked the > post for later study, but that was several days ago, so I just wanted > to say that I'm still looking at it. It's an area of Python that I've > somewhat purposely stayed away from. Hehe. Keep away - once you get dive into it, it'll be hard go get out. It's really addictive :D > > I use them, a lot, specially when writing decorators... Many times I > > just want to 'mark' the decorated functions so I can inspect those > > marks later. I'd rather have a semi-private namespace for each pair > > ([group of]calling function[s], object), > > Right, thus the usefulness of a static tool that can find all those > places where extra attributes are created. Basically I can see three > approaches to this question: Btw, this thread inspired me to do another proof-of-concept stuff that I may be using more seriously. Too bad I don't have anywhere to upload it right now... Anyway, it looks like this: suppose I need to attach some attributes to the object "x", but I don't want to do x.attr import namespaces # my module class my_private_namespace(namespaces.Namespace): pass def this_function_stores_the_attr(x): ns = my_private_namespace(x) ns.attr = 5 # I'm creating an attribute on the fly # but at least I'm not touching x. def this_function_reads_the_attr(x): ns = my_private_namespace(x) print ns.attr > 1) Program in a style where you create and modify attributes all over > the place willy-nilly, with no controls whatsoever, either automatic > or stylistic. From experience (it is a common style in Javascript) I > can say this is a big mess and I think no experienced Python > programmers recommend it. Indeed. Though I don't consider myself 'experienced', I certainly don't recommend it. > 2) Have mandatory encapsulation like Java's, no way to escape. Bruno > and yourself vehemently object to this, Russ P seems to want it, my > view is that it's not in the Python spirit, so I can accept the > argument that those who really want this are better off choosing > another language. Btw, I noticed a funny side effect of my 'namespaces' module (needs a LOT of work, this was the first time I touched weak references. I should find some place to upload the module): ===== import namespaces class public(namespaces.Namespace): pass class private(namespaces.Namespace): # the initializer could check if pass # its called from outside the class. Performance penalty. class A(object): """dummy class A, with one 'private' attribute x, and one normal 'attribute' x.""" def __init__(self): self.x = id(self) # normal attr pub = public(self) pub.f = self.f priv = private(self) priv.x = "this is the private" def f(self): print "normal x: ", self.x priv = private(self) print "private x: ", priv.x >>> a = A() >>> dir(a) ['__class__', <normal __attrs__>, 'f', 'x'] >> a.f() normal x: 147956684 private x: this is the private >>> p = public(a) >>> dir(p) # Look, there is no 'x' attribute! ['__class__', <normal __attrs__>, 'f'] >>> p.f() # but f still works! normal x: 147956684 private x: this is the private ====== Of course, without checks in 'private', one could say priv = private(a); priv.x, but the most interesting part, for me at least, was the ability to define a 'public' interface for a, that contains no attribute directly referencing the object 'a' with its internals - only the names explicitly declared on the 'interface'. Indirectly... well, p.f.im_self will return back the 'a' object. Bah, I'm ranting now. I just got carried away with my little experiment. Sorry. Ah, and yes, metaclasses are dangerously addictive :D > 3) Program in a style where creating new attributes outside the > initializer is normally avoided by convention, but it is possible and > sometimes desirable to break the convention. This seems reasonable > and Pythonic to me. But, any place I break the convention, I should > be able to say "I broke the convention here for such and such a > reason". And (this seems to be a bone of contention) IMO, it would be > good to be able to audit a large codebase with a tool like Pylint, to > automatically find all the places where such breakages occur. Right > now there seems to be no way to do that reliably, short of using > something like your special metaclass instead of the standard one for > just about everything. Well, I agree. Each and every one of those convention-breakages should be well documented, and pylint should be able to pick them up. Pylint does that already (see example below), I don't know if it lets you "document" it explicitly. I think Eclipse catches some of that stuff. My metaclass... shouldn't be used for anything serious :D. === breaklint.py === (no, it didn't break pylint) class A(object): def __init__(self): self.a = 5 def f(self): self.b = 7 # creating outside the init def g(self): print self.b # only if f runs first print self.c # and this one doesn't exist a = A() a.c = 8 a.f() a.g() a.d = "new var" # outside the class definition ================== $ pylint breaklint.py [...] W: 13: Attribute 'c' defined outside __init__ W: 7:A.f: Attribute 'b' defined outside __init__ W: 16: Attribute 'd' defined outside __init__ [...] Your code has been rated at -1.54/10 ===== > Your example about decorators (used on classes that don't expect to be > wrapped by them) is a good one but narrow enough that there could be a > special arrangement for it in a hypothetical auditing tool. Indeed. I'll take a look at pylint's config file. -- Luis Zarrabeitia Facultad de Matemática y Computación, UH http://profesores.matcom.uh.cu/~kyrie -- http://mail.python.org/mailman/listinfo/python-list