Re: on writing a while loop for rolling two dice
On 28/08/2021 14:00, Hope Rouselle wrote: def how_many_times(): x, y = 0, 1 c = 0 while x != y: c = c + 1 x, y = roll() return c, (x, y) --8<---cut here---end--->8--- Why am I unhappy? I'm wish I could confine x, y to the while loop. The introduction of ``x, y = 0, 1'' must feel like a trick to a novice. How would you write this? Thank you! I'd probably hide the while loop under the rug: >>> import random >>> def roll_die(): while True: yield random.randrange(1, 7) Then: >>> def hmt(): for c, (x, y) in enumerate(zip(roll_die(), roll_die()), 1): if x == y: return c, (x, y) >>> hmt() (1, (2, 2)) >>> hmt() (4, (4, 4)) >>> hmt() (1, (5, 5)) OK, maybe a bit complicated... but does it pay off if you want to generalize? >>> def roll_die(faces): while True: yield random.randrange(1, 1 + faces) >>> def hmt(faces, dies): for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1): if len(set(d)) == 1: return c, d >>> hmt(10, 1) (1, (2,)) >>> hmt(10, 2) (3, (10, 10)) >>> hmt(10, 3) (250, (5, 5, 5)) >>> hmt(1, 10) (1, (1, 1, 1, 1, 1, 1, 1, 1, 1, 1)) You decide :) -- https://mail.python.org/mailman/listinfo/python-list
Re: on the popularity of loops while and for
> On 28 Aug 2021, at 22:42, Hope Rouselle wrote: > > I'd like get a statistic of how often each loop is used in practice. > > I was trying to take a look at the Python's standard libraries --- those > included in a standard installation of Python 3.9.6, say --- to see > which loops are more often used among while and for loops. Of course, > since English use the preposition ``for'' a lot, that makes my life > harder. Removing comments is easy, but removing strings is harder. So > I don't know yet what I'll do. > > Have you guys ever measured something like that in a casual or serious > way? I'd love to know. Thank you! I am interesting in why you think that choice of while vs. for is about popularity? Surely the choice is made in most cases by the algorithm? If you have an iterator then you use for. Of course you can use while instead of for but in code review that will get queried. Barry > -- > https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On 29/08/2021 20.06, Peter Otten wrote: ... > OK, maybe a bit complicated... but does it pay off if you want to > generalize? > def roll_die(faces): > while True: yield random.randrange(1, 1 + faces) > def hmt(faces, dies): > for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1): > if len(set(d)) == 1: return c, d Curiosity: why not add dies as a parameter of roll_die()? Efficiency: - wonder how max( d ) == min( d ) compares for speed with the set() type constructor? - alternately len( d ) < 2? - or len( d ) - 1 coerced to a boolean by the if? - how much more efficient is any of this (clever thinking!) than the OP's basic, simpler, and thus more readable, form? English language 'treachery': - one die - multiple dice (probably not followed in US-English (can't recall), particularly on computers running the Hollywood Operating System). Continuous Education: Thanks for the reminder that enumerate() can be seeded with a "start" value! -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list wrote: > Efficiency: > - wonder how max( d ) == min( d ) compares for speed with the set() type > constructor? That may or may not be an improvement. > - alternately len( d ) < 2? > - or len( d ) - 1 coerced to a boolean by the if? Neither of these will make any notable improvement. The work is done in constructing the set, and then you're taking the length. How you do the comparison afterwards is irrelevant. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On 29/08/2021 12:13, dn via Python-list wrote: On 29/08/2021 20.06, Peter Otten wrote: ... OK, maybe a bit complicated... but does it pay off if you want to generalize? def roll_die(faces): while True: yield random.randrange(1, 1 + faces) def hmt(faces, dies): for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1): if len(set(d)) == 1: return c, d Curiosity: why not add dies as a parameter of roll_die()? Dunno. Maybe because I've "always" [1] wanted a version of random.randrange() that generates values indefinitely. It would need to check its arguments only once, thus leading to some extra Efficiency: - wonder how max( d ) == min( d ) compares for speed with the set() type constructor? I did the simplest thing, speed was not a consideration. If it is, and dies (sorry for that) is large I'd try first = d[0] all(x == first for x in d) # don't mind one duplicate test For smaller numbers of dice I'd unpack (first, *rest) inside the for loop. But it's a trade-off, you' have to measure if/when it's better to go through the whole tuple in C. - alternately len( d ) < 2? - or len( d ) - 1 coerced to a boolean by the if? - how much more efficient is any of this (clever thinking!) than the OP's basic, simpler, and thus more readable, form? It really isn't efficiency, it's a (misled?) sense of aesthetics where I've come to prefer - for-loops over while, even when I end up with both to get the desired for - enumerate() over an explicit counter even though there is the extra unpack, and you still need to initialize the counter in the general case: for i, item in enumerate([]): pass print(f"There are {i+1} items in the list.") # Oops English language 'treachery': - one die - multiple dice You might have inferred that I knew (or had looked up) the singular of dice, so this is but a momentary lapse of reason. It hurts me more than you, trust me. Not as much, as going on record with confusing they're and their, but still ;) (probably not followed in US-English (can't recall), particularly on computers running the Hollywood Operating System). I've come to the conclusion that International English is hopelessly and inevitably broken. That's the price native speakers have to pay for having they're (oops, I did it again!) language used as lingua franca. Continuous Education: Thanks for the reminder that enumerate() can be seeded with a "start" value! [1] I think I've suggested reimplementing the whole module in terms of generators -- can't find the post though. -- https://mail.python.org/mailman/listinfo/python-list
code to initialize a sequence
In the code attached below, the A-variant is from somebody else who knows Python better than I. But I do not like to just use any code without having a grasp, specifically the line in* bold*, so I wrote the B-variant which gives the same results. The C-variant is identical to A and is there for verification: after resetting the seed I expect the same sequence. The D-variant is closer to the way I code, and it does not work. import random from random import randint, seed def generate_sequence(length, n_unique): *return [randint(0, n_unique-1) for k in range(length)]* def generate_sequence_JP(length, n_unique): LI = [] for k in range(length): LI.append(randint(0, n_unique-1)) return(LI) def generate_sequence_EXPLICIT(length, n_unique): X =[None] * length for i in range(length): X[i] = [randint(0, n_unique-1)] return X # # MAIN PROGRAM # random.seed(2) A = generate_sequence(4, 10 ) random.seed(2) B = generate_sequence_JP(4, 10) random.seed(2) C = generate_sequence(4, 10 ) random.seed(2) D = generate_sequence_EXPLICIT(4, 10 ) print(A) print(type(A)) print('-') print(B) print(type(B)) print('-') print(C) print(type(C)) print('-') print(D) print(type(D)) Regards, Joseph Pareti - Artificial Intelligence consultant Joseph Pareti's AI Consulting Services https://www.joepareti54-ai.com/ cell +49 1520 1600 209 cell +39 339 797 0644 -- https://mail.python.org/mailman/listinfo/python-list
Re: code to initialize a sequence
On 29/08/2021 20:44, joseph pareti wrote: In the code attached below, the A-variant is from somebody else who knows Python better than I. But I do not like to just use any code without having a grasp, specifically the line in* bold*, so I wrote the B-variant which gives the same results. The C-variant is identical to A and is there for verification: after resetting the seed I expect the same sequence. The D-variant is closer to the way I code, and it does not work. So you do you want us to debug the _EXPLICIT version? The assignment > X[i] = [randint(0, n_unique-1)] creates a list with one element and turns it into an item in the list X. You don't want a list, you want the numerical value, the straight-forward way to achieve that being X[i] = randint(0, n_unique-1) An alternative is to assign to a slice X[i:i+1] = [randint(...)] but that would only make sense if the right-hand-side list weren't created in the line and ditched immediately afterwards. import random from random import randint, seed def generate_sequence(length, n_unique): *return [randint(0, n_unique-1) for k in range(length)]* The above is the most pythonic of the three versions. Once you understand how for loops with a list.append() are turned into comprehensions it will be easy to write and read that style. Definitely worth learning and adopting. def generate_sequence_JP(length, n_unique): LI = [] for k in range(length): LI.append(randint(0, n_unique-1)) return(LI) This is also fine and often used when the loop body is a bit more complex, but def generate_sequence_EXPLICIT(length, n_unique): X =[None] * length for i in range(length): X[i] = [randint(0, n_unique-1)] return X this is garbage even when it works, usually indicative of premature optimization. Random (yeah!) remark: Python uses half-open intervals (i. e. intervals that include the lower bound, but not the upper bound) almost everywhere. randint() is one exception. Personally I prefer its conformist sister randrange(); with that randint(0, n_unique-1) becomes randrange(n_unique) # # MAIN PROGRAM # random.seed(2) A = generate_sequence(4, 10 ) random.seed(2) B = generate_sequence_JP(4, 10) random.seed(2) C = generate_sequence(4, 10 ) random.seed(2) D = generate_sequence_EXPLICIT(4, 10 ) print(A) print(type(A)) print('-') print(B) print(type(B)) print('-') print(C) print(type(C)) print('-') print(D) print(type(D)) Regards, Joseph Pareti - Artificial Intelligence consultant Joseph Pareti's AI Consulting Services https://www.joepareti54-ai.com/ cell +49 1520 1600 209 cell +39 339 797 0644 -- https://mail.python.org/mailman/listinfo/python-list
Re: Making command-line args available to deeply-nested functions
Loris Bennett ezt írta (időpont: 2021. aug. 26., Cs, 16:02): > George Fischhof writes: > > [snip (79 lines)] > > >> > Hi, > >> > > >> > Also you can give a try to click and / or typer packages. > >> > Putting args into environment variables can be a solution too > >> > All of these depends on several things: personal preferences, > colleagues > >> / > >> > firm standards, the program, readability, variable accessibility (IDE > >> > support, auto completition) (env vars not supported by IDEs as they > are > >> not > >> > part of code) > >> > >> Thanks for the pointers, although I have only just got my head around > >> argparse/configargparse, so click is something I might have a look at > >> for future project. > >> > >> However, the question of how to parse the arguments is somewhat separate > >> from that of how to pass (or not pass) the arguments around within a > >> program. > > [snip (16 lines)] > > > > Hi, > > I thought not just parsing, but the usage method: you add a decorator to > > the function where you want to use the parameters. This way you do not > have > > to pass the value through the calling hierarchy. > > > > Note: typer is a newer package, it contains click and leverages command > > line parsing even more. > > Do you have an example of how this is done? From a cursory reading of > the documentation, it didn't seem obvious to me how to do this, but then > I don't have much understanding of how decorators work. > > Cheers, > > Loris > > > -- > This signature is currently under construction. > -- > https://mail.python.org/mailman/listinfo/python-list Hi, will create a sample code on Monday - Tuesday BR, George -- https://mail.python.org/mailman/listinfo/python-list
Re: PEP Idea: Real private attribute
No, a class ("the class that I'm lexically inside") cannot be accessed from outside of the class. This is why I'm planning to offer it as a core feature because only the parser would know. There's apparently no elegant solution if you want to implement it yourself. You'll need to write self.__privs__[__class__, "foo"], whenever you want to use the feature and even wrapping it in superclasses won't remedy it, because the parent class isn't aware which class you're inside. It seems to me name mangling must have been an ad-hoc solution in a language that it doesn't really fit when it could have been implemented in a much more cogent way. Best, [image: image.gif][image: image.gif] Mehrzad On Sun, 29 Aug 2021 at 02:18, Chris Angelico wrote: > On Sun, Aug 29, 2021 at 7:40 AM Mehrzad Saremi > wrote: > > > > Python currently uses name mangling for double-underscore attributes. > Name > > mangling is not an ideal method to avoid name conflicting. There are > > various normal programming patterns that can simply cause name > conflicting > > in double-underscore members. A typical example is when a class is > > re-decorated using the same decorator. The decorator can not take > > double-underscore members without name conflicts. For example: > > > > ``` > > @custom_decorator("a") > > @custom_decorator("b") > > class C: > > pass > > ``` > > > > The `@custom_decorator` wrapper may need to hold private members, but > > Python's current name conflict resolution does not provide any solution > and > > the decorator cannot hold private members without applying tricky > > programming methods. > > > > Another example is when a class inherits from a base class of the same > name. > > > > ``` > > class View: > > """A class representing a view of an object; similar to > > numpy.ndarray.view""" > > pass > > > > class Object: > > class View(View): > > """A view class costumized for objects of type Object""" > > pass > > ``` > > > > Again, in this example, class `Object.View` can't take double-underscore > > names without conflicting with `View`'s. > > > > My idea is to introduce real private members (by which I do not mean to > be > > inaccessible from outside the class, but to be guaranteed not to conflict > > with other private members of the same object). These private members are > > started with triple underscores and are stored in a separate dictionary > > named `__privs__`. Unlike `__dict__` that takes 'str' keys, `__privs__` > > will be a double layer dictionary that takes 'type' keys in the first > > level, and 'str' keys in the second level. > > > > For example, assume that the user runs the following code: > > ``` > > class C: > > def __init__(self, value): > > self.___member = value > > > > c = C("my value") > > ``` > > > > On the last line, Python's attribute setter creates a new entry in the > > dictionary with key `C`, adds the value "my value" to a new entry with > the > > key 'member'. > > > > The user can then retrieve `c.___member` by invoking the `__privs__` > > dictionary: > > > > ``` > > print(c.__privs__[C]['member']) # prints 'my value' > > ``` > > > > Note that, unlike class names, class objects are unique and there will > not > > be any conflicts. Python classes are hashable and can be dictionary keys. > > Personally, I do not see any disadvantage of using __privs__ over name > > mangling/double-underscores. While name mangling does not truly guarantee > > conflict resolution, __privs__ does. > > Not entirely sure how it would know the right type to use (subclassing > makes that tricky), but whatever your definition is, there's nothing > stopping you from doing it yourself. Don't forget that you have > __class__ available if you need to refer to "the class that I'm > lexically inside" (that's how the zero-arg super() function works), so > you might do something like self.__privs__[__class__, "foo"] to refer > to a thing. > > ChrisA > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: PEP Idea: Real private attribute
On Mon, Aug 30, 2021 at 5:49 AM Mehrzad Saremi wrote: > > No, a class ("the class that I'm lexically inside") cannot be accessed from > outside of the class. This is why I'm planning to offer it as a core > feature because only the parser would know. There's apparently no elegant > solution if you want to implement it yourself. You'll need to write > self.__privs__[__class__, "foo"], whenever you want to use the feature and > even wrapping it in superclasses won't remedy it, because the parent class > isn't aware which class you're inside. It seems to me name mangling must > have been an ad-hoc solution in a language that it doesn't really fit when > it could have been implemented in a much more cogent way. > If the parent class isn't aware which class you're in, how is the language going to define it? Can you give a full run-down of the semantics of your proposed privs, and how it's different from something like you just used above - self.__privs__[__class__, "foo"] - ? If the problem is the ugliness alone, then say so; but also, how this would work with decorators, since you specifically mention them as a use-case. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On 29/08/2021 22.24, Chris Angelico wrote: > On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list > wrote: >> Efficiency: >> - wonder how max( d ) == min( d ) compares for speed with the set() type >> constructor? > > That may or may not be an improvement. > >> - alternately len( d ) < 2? >> - or len( d ) - 1 coerced to a boolean by the if? > > Neither of these will make any notable improvement. The work is done > in constructing the set, and then you're taking the length. How you do > the comparison afterwards is irrelevant. It was far too late for either of us (certainly this little boy) to be out-and-coding - plus an excellent illustration of why short-names are a false-economy which can quickly (and easily) lead to "technical debt"! The "d" is a tuple (the 'next' returned from the zip-output object) consisting of a number of die-throw results). Thus, can toss that into len() without (any overhead of) conversion to a set. -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On Mon, Aug 30, 2021 at 9:53 AM dn via Python-list wrote: > > On 29/08/2021 22.24, Chris Angelico wrote: > > On Sun, Aug 29, 2021 at 8:14 PM dn via Python-list > > wrote: > >> Efficiency: > >> - wonder how max( d ) == min( d ) compares for speed with the set() type > >> constructor? > > > > That may or may not be an improvement. > > > >> - alternately len( d ) < 2? > >> - or len( d ) - 1 coerced to a boolean by the if? > > > > Neither of these will make any notable improvement. The work is done > > in constructing the set, and then you're taking the length. How you do > > the comparison afterwards is irrelevant. > > It was far too late for either of us (certainly this little boy) to be > out-and-coding - plus an excellent illustration of why short-names are a > false-economy which can quickly (and easily) lead to "technical debt"! > > > The "d" is a tuple (the 'next' returned from the zip-output object) > consisting of a number of die-throw results). Thus, can toss that into > len() without (any overhead of) conversion to a set. Oh. Well, taking the length of the tuple is fast... but useless. The point was to find out if everything in it was unique :) Conversion to set tests this because the length of the set is the number of unique elements; checking max and min works because two scans will tell you if they're all the same; using all with a generator stops early if you find a difference, but requires back-and-forth calls into Python code; there are various options, and the choice probably won't make a material performance difference anyway :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: PEP Idea: Real private attribute
The proposed semantics would be the same as self.__privs__[__class__, "foo"]; yes I can say the problem is ugliness. The following is an example where name mangling can be problematic (of course there are workarounds, yet if double-underscores are meant to represent class-specific members, the following behavior is an infringement of the purpose). ``` class Weighable: def weight(self): raise NotImplementedError() class AddWeight: def __init__(self, weight): self.weight = weight def __call__(self, cls): class Wrapper(cls, Weighable): __weight = self.weight def weight(self): return self.__weight + (cls.weight(self) if issubclass(cls, Weighable) else 0) # Unexpected behavior return Wrapper @AddWeight(2.0) @AddWeight(1.0) class C: pass print(C().weight()) ``` > If the parent class isn't aware which class you're in, how is the language going to define it? I mean if you want to implement self.__privs__[__class__, "foo"] in a parent class using __setattr__/__getattribute__ the __class__ value is unknown. On Mon, 30 Aug 2021 at 00:26, Chris Angelico wrote: > On Mon, Aug 30, 2021 at 5:49 AM Mehrzad Saremi > wrote: > > > > No, a class ("the class that I'm lexically inside") cannot be accessed > from > > outside of the class. This is why I'm planning to offer it as a core > > feature because only the parser would know. There's apparently no elegant > > solution if you want to implement it yourself. You'll need to write > > self.__privs__[__class__, "foo"], whenever you want to use the feature > and > > even wrapping it in superclasses won't remedy it, because the parent > class > > isn't aware which class you're inside. It seems to me name mangling must > > have been an ad-hoc solution in a language that it doesn't really fit > when > > it could have been implemented in a much more cogent way. > > > > If the parent class isn't aware which class you're in, how is the > language going to define it? > > Can you give a full run-down of the semantics of your proposed privs, > and how it's different from something like you just used above - > self.__privs__[__class__, "foo"] - ? If the problem is the ugliness > alone, then say so; but also, how this would work with decorators, > since you specifically mention them as a use-case. > > ChrisA > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Re: on writing a while loop for rolling two dice
On 30/08/2021 00.47, Peter Otten wrote: > On 29/08/2021 12:13, dn via Python-list wrote: >> On 29/08/2021 20.06, Peter Otten wrote: >> ... >>> OK, maybe a bit complicated... but does it pay off if you want to >>> generalize? >>> >> def roll_die(faces): >>> while True: yield random.randrange(1, 1 + faces) >>> >> def hmt(faces, dies): >>> for c, d in enumerate(zip(*[roll_die(faces)]*dies), 1): >>> if len(set(d)) == 1: return c, d >> >> >> Curiosity: >> why not add dies as a parameter of roll_die()? > > Dunno. Maybe because I've "always" [1] wanted a version of > random.randrange() that generates values indefinitely. It would need to > check its arguments only once, thus leading to some extra Each code-unit should do one job, and do it well! SRP... >> Efficiency: >> - wonder how max( d ) == min( d ) compares for speed with the set() type >> constructor? > > I did the simplest thing, speed was not a consideration. If it is, and > dies (sorry for that) is large I'd try > > first = d[0] > all(x == first for x in d) # don't mind one duplicate test > > For smaller numbers of dice I'd unpack (first, *rest) inside the for > loop. But it's a trade-off, you' have to measure if/when it's better to > go through the whole tuple in C. For larger numbers of dice, and presuming a preference for an inner-function which rolls only a single die per call; would it be more efficient to test each individual die's value against the first, immediately after its (individual) roll/evaluation (rinse-and-repeat for each die thereafter)? This, on the grounds that the first mis-match obviates the need to examine (or even roll), any other die/dice in the collection. OTOH the simulation of rolling n-number of dice, as would happen in the real-world, would be broken by making the computer's algorithm more efficient (rolling until the first non-equal value is 'found'). Does that mean the realism of the model dies? (sorry - no, I'm not sorry - you deserved that!) Does one "roll" a die, or "shake the dice"??? We don't know the OP's requirements wrt to execution-efficiency. However, as you (also) probably suffered, such exercises regularly feature in stats and probability courses. Sometimes 'the numbers' are quite large in order to better-illustrate ("smooth") distribution characteristics, etc. I have a love?hate relationship with questions of Python and 'efficiency'. Today, discovered that using a cut-down Linux version (on AWS) was actually slower than using a full-fat distribution - upon analysis, my friendly 'expert' was able to point the finger at the way the two distros compiled/prepared/distribute the(ir) Python Interpreter. (I'm glad he thought such investigation 'fun'!) All of which further complicates the business of design, given we already know of situations where approach-a will run faster than approach-b, on your machine; yet the comparison may be reversed on mine. This discussion forms a sub-set of that: when to use the built-in functions (implemented in C) because they are (claimed to be) more efficient than another approach - and, when one approach using a built-in function might be faster than another 'built-in'/C-coded approach. ("small things amuse small minds" - mind how you describe my mind!) "Bottom line": I prefer to think of Python's "efficiency" as reflected in the amount of my time that is needed, in order to complete a project! >> - alternately len( d ) < 2? >> - or len( d ) - 1 coerced to a boolean by the if? >> - how much more efficient is any of this (clever thinking!) than the >> OP's basic, simpler, and thus more readable, form? > > It really isn't efficiency, it's a (misled?) sense of aesthetics where > I've come to prefer > > - for-loops over while, even when I end up with both to get the desired for > > - enumerate() over an explicit counter even though there is the extra > unpack, and you still need to initialize the counter in the general case: > > for i, item in enumerate([]): pass > print(f"There are {i+1} items in the list.") # Oops Next thing you'll be using for-else... [insane giggling] It's interesting how we arrive at these views (as a trainer I spend a lot of time trying to detect how learners build their mental maps, or "models", of each topic). I've always had a clear 'formula'/rule/hobgoblin: if the number of loops can be predicted, use 'for', otherwise use 'while'. Of course, Python alters that view because it offers a for-each, which means that I don't need to know the number of loops, only that the loop will cycle through each item in the iterable. It used to be a far simpler world! That said, I really miss the option of while controlling the loop with a pre-condition AND having a repeat...until controlling the loop with a post-condition - the former enabling >=0 loops; the latter, requiring at least one! Using enumerate() may be a matter of aesthetics (English-English spelling!). However, it is a basic Python idiom. It is as much