Sometimes when I post something I get back comments and evaluate them and learn quite a bit. I then reply and debate every little point and it can continue for a few rounds.
I don't seem to be in that mood today so let me simply restate my entire post in a few sentences with no examples, no lectures, no advice on what anyone else can do and very little for anyone to bother replying to. Here goes: Sometimes when I run up against a wall and find that a solution to a problem does not work because things may not work as I expected, I pause. I reconsider what I actually need to get done. Then I look to see if I can come up with other ways to do it that will work while still getting the important parts done. Failing that, I ask if perhaps there is another tool, such as another programming language that is a better fit for the task. And, if the work needed seems excessive, I ask if perhaps the problem does not really need to be solved by me and I move on. -----Original Message----- From: Python-list <python-list-bounces+avigross=verizon....@python.org> On Behalf Of Chris Angelico Sent: Thursday, December 27, 2018 5:11 PM To: Python <python-l...@python.org> Subject: Re: dangerous class neighborhood On Fri, Dec 28, 2018 at 8:47 AM Avi Gross <avigr...@verizon.net> wrote: > Question 2: Do you want the variables available at the class level or > at the instance level? For constants, definitely put them on the class. They'll be available on instances as well ("for free", if you like). For mutables, obviously you need to decide on a case-by-case basis. > Question 3: Which python variations on syntactic sugar, such as list > comprehensions, get expanded invisibly in ways that make the problem > happen by asking for variables to be found when no longer in the visible range? The oddities with comprehensions were tackled partly during the discussion of PEP 572. If you want to know exactly why this isn't changing, go read a few hundred emails on the subject. A lot of the main points are summarized in the PEP itself: https://www.python.org/dev/peps/pep-0572/ > There may be matters of efficiency some would consider but some of the > examples seen recently seemed almost silly and easy to compute. The > people asking about this issue wanted to define a bunch of CONSTANTS, > or things that might as well be constants, like this: > > > > def Foo(): > > A = ("male", "female", "other") > > B = [ kind[0] for kind in A ] # First letters > only > > # And so on making more constants like a dictionary > mapping each string to a number or vice versa. > > > > All the above can be evaluated at the time the class is defined but > unintuitive scope rules make some operations fail as variables defined > in the scope become unavailable to other things that SEEM to be > embedded in the same scope. If you write simple and Pythonic code, these will almost always work perfectly. The recent thread citing an oddity worked just fine until it was written to iterate over range(len(x)) instead of iterating directly. > If they are ONLY to be used within an instance of Foo or invoked from > within there, there may be a fairly simple suggestion. If you already > have a __init__ method, then instantiate the variables there carefully > using the self object to reference those needed. But why? __init__ should initialize an instance, not class-level constants. A Python class is not restricted to just methods, and there's no reason to avoid class attributes. > Create a function either outside the class or defined within. Have it > do any internal calculations you need in which all internal variables > can play nicely with each other. Then let it return all the variables > in a tuple like > this: > > def make_sexual_constants(): > > A = . > > B = . > > C = f(A,B) > > D = . > > def Foo(): > > (A, B, C, D) = make_sexual_constants(): Lovely. Now you have to define your variables once inside the function, then name them a second time in that function's return statement, and finally name them all a *third* time in the class statement (at least, I presume "def Foo():" is meant to be "class Foo:"). A mismatch will create bizarre and hard-to-debug problems. What do you actually gain? Can you show me real-world code that would truly benefit from this? > Can we agree that the class Foo now has those 4 variables defined and > available at either the class level or sub-class or instance levels? > But the values are created, again, in a unified safe environment? Unified? No more so than the class statement itself. Safe? Definitely not, because of the mandatory duplication of names. > As noted in section 3, it would be good to know what python features > may be unsafe in this kind of context. I had an unrelated recent > discussion where it was mentioned that some proposed feature changes > might not be thread safe. Valid consideration when that may lead to hard-to-explain anomalies. Uhh..... nope, that's nothing but FUD. There is no reason to believe that some language features would be "unsafe". > We now hear that because a list comprehension can be unwound > internally into a "while" loop and an "if" statement and that some > parts may expand to calls to a "range" statement, perhaps some > variables are now in more deeply embedded contexts that have no access to any class variables. No idea what you're looking at. A comprehension can be unwound in a fairly straight-forward way, although there are some subtleties to them. B = [ kind[0] for kind in A ] # equivalent to, approximately: def listcomp(iter): result = [] for kind in iter: result.append(kind[0]) return result B = listcomp(A) For casual usage, you can describe a list comp very simply and neatly: B = [ kind[0] for kind in A ] # equivalent to, more approximately: B = [] for kind in A: B.append(kind[0]) Nothing here expands to a call to range(), nothing has a while loop. The only way you'll get an "if" is if you had one in the comprehension itself. > I think that > is quite reasonable; hence my suggestion we need to know which ones to > avoid, or use a workaround like expanding it out ourselves and perhaps > carefully import variables into other contexts such as by passing the > variable into the function that otherwise cannot access it from a > point it can still be seen. Sure. If the comprehension doesn't work for you, just put a for loop inside your class statement. This is not a problem. > Least, but at least last, I ask if the need really exists for these > variables as constants versus functions. If creating C this way runs > into problems, but A and B are fine, consider making a method with > some name like > Foo.get_C() that can see A and B and do the calculation and yet return > the value of C needed. Less efficient but . Definitely not. That would imply that the value of C might change, or might have significant cost, or in some other way actually merits a getter function. Python isn't built to encourage that. Class scope has edge cases, to be sure, but they're much more notable in carefully-crafted exploratory code than in actual real-world code. ChrisA -- https://mail.python.org/mailman/listinfo/python-list _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor