Rob Williscroft wrote: > Steven D'Aprano wrote in > news:[EMAIL PROTECTED] in > comp.lang.python: > > >>Quoting Rob Williscroft: >> >> >>> > def translate( text ) >>> > import string all=string.maketrans('','') >>> > badcars=all.translate(all,string.letters+string.digits) >>> > TABLE = string.maketrans(badcars,'_'*len(badcars)) >>> > >>> > global translate >>> > def translate( text ): >>> > return text.translate(TABLE) >>> > >>> > return translate( text ) >> >>This is a difficult piece of code to understand and maintain. > > > Its 8 lines, of self contained code. It does everyting its supposed to do > and nothing its not.
I didn't say it didn't work. I didn't say it was buggy. I didn't say it was too long, or had too many dependencies. Brevity is not always a blessing -- that's how we get obfuscated C and Perl programs that fit the most functionality into the fewest lines. In this _specific_ case, perhaps I was a little harsh. I've been badly burnt before with self-modifying code: once burnt, twice shy. I'm still uncomfortable with your code, but after spending more time following the program logic, I'm less uncomfortable with it than I was. However, see additional comments below. >>You have >>a function called translate, which in turn calls the string >>translate() method. That's okay. But then you have a global variable >>*also* called translate -- does that refer to the same function? > > This is how globals work in python, if you wish to (re)bind to a global > before reading it at function scope, you need to say so. Yes, I know that. Sorry, my rhetorical question gave you the wrong impression. I wasn't questioning how globals work, I was attempting (poorly) to show the mental hoops a new programmer unfamiliar with the code has to jump through to get it straight in his head. >>Is >>this self-modifying code? That is a dangerous, hard to debug, hard to >>understand technique that is too-clever-by-half. > > Maybe so, but if true, python as a language is too-clever-by-half. Most languages can create self-modifying code. That's not the question. The question is whether developers should write self-modifying code, not whether language designers should prohibit it. >>Then you create a local variable, also called translate, also a > > No, that isn't how globals work in python, there is no local called > translate above. Terminology conflict: I'm refering to the fact that your second translate function definition is written locally to the first top-level translate. My bad: I should have said nested rather than local. >>function, which simply calls the translate method of its argument. A >>waste of a function, when all you need to do is call the pre-existing >>translate method. If I have understood this code correctly, the >>*local* translate is bound to the *global* translate, which is the >>function being defined. > > Close but there isn't, and never was, a *local* translate function. Agreed: I meant nested. >>And lastly, just to complete the confusion, the original function >>itself appears to call itself -- presumably the rebound copy that >>points to what was the local copy -- recursively, with the same >>argument. > > > def f() > global g > def g(): > return "something" > return g() > > f() is a function that (re)creates a global function g() and calls it. > Is it just that translate() rebinds itself that is too much, or do you > object to f() too ? I do object to f() but only because its useless. Yes, unless there is a very good reason for rebinding g dynamically, I would be very cautious of using that technique. It means that g changes its behaviour, not because of the input it gets, but because of when it is called. g does a certain thing, then in some obscure corner of your program, hardly noticed, some function or method calls f and suddenly g acts completely differently. In principle, you the developer may not even be able to predict when this change of behaviour will happen. It comes with the considerable risk that your developers are desperately trying to read and understand g as it first was, and not understanding why it is acting differently. It is a technique that begs to be misused: if you think you can write confusing, baroque code with GOTO, you can do worse with dynamically rebinding functions and self-modifying code. Just as there are good uses for GOTO, I am happy to admit that there are good cases for self-modifying code. But not for something as trivial as creating an alias for a string method. All meta-programming should be used with care, and only when the more, shall we say traditional, alternatives have serious deficiencies. At the very least it should be documented in detail. >>That's a nifty piece of code for showing how clever you are at writing >>mildly obfuscated code. But for commercial use, where the code has to >>be maintained and debugged, it is a terrible idea. > > 8 lines of self contained code are a terrible idea !, you have IMO a > very strange idea of what is or isn't maintainable. No. I work for an IT company, and I know the sort of code we are called on to maintain, and the sort of developers that are available. It isn't that eight lines are too many, but that the behaviour of the function changes. The fact that it is self-modifying just makes it even less intuitive. Our human intuition of behaviour is that things act a certain way, and while the behaviour should change depending on the input, it shouldn't change radically from one time to the next. For example, we understand that a ball thrown at the ground will bounce at a different angle depending on the angle it was tossed at, but we would be shocked to see it bounce the first time, then stick to the ground the second, then start bouncing again the tenth time we toss it. We intuitively understand changes in state, eg we have little problem understanding rebinding x from a float to a string, because that's like changing a glass that holds water to broken shards that don't (except better: we can reverse the transformation of x). But we have little intuitive about glasses that hold water, then don't hold water -- that's why we get worried and confused when people suddenly start acting out of character: behaviour changes, without any visible change of state. Any programming technique that acts against human intuition about how objects "should" behave will cause many developers confusion and difficulty, and anything which causes developers confusion and difficulty will generally lead to buggy code and always to higher costs. (We have to pay our developers for their time when they are confused, not just when they are coding in the zone.) That's why meta-programming and self-modifying code should be used with care, and documented well. You might understand it, but the next guy who comes along to maintain your code is going to be faced with the code equivalent of somebody acting out of character. > Is using generators and decorators a terrible idea too ? Generators don't mysteriously change behaviour, except in the limited sense that they halt when they run out of data, and that is perfectly intuitive. Halting when you run out of data is so intuitive that one common bug in code is to forget to program in a halting condition, especially in recursive functions but even in while loops -- we just expect that it will stop when it is done. The principle of how generators work takes a little understanding, but once you understand the principle, understanding any specific generator is no harder than understanding the non-generator equivalent code, and probably much easier. Decorators, well, I've never used them, and I still don't understand why people seem so excited about them, so I don't have an opinion. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list