Re: name for new Enum decorator
On 5/28/21 5:23 AM, Ethan Furman wrote: Greetings! The Flag type in the enum module has had some improvements, but I find it necessary to move one of those improvements into a decorator instead, and I'm having a hard time thinking up a name. What is the behavior? Well, a name in a flag type can be either canonical (it represents one thing), or aliased (it represents two or more things). To use Color as an example: class Color(Flag): RED = 1 # 0001 GREEN = 2 # 0010 BLUE = 4 # 0100 PURPLE = RED | BLUE # 0101 WHITE = RED | GREEN | BLUE # 0111 The flags RED, GREEN, and BLUE are all canonical, while PURPLE and WHITE are aliases for certain flag combinations. But what if we have something like: class Color(Flag): RED = 1 # 0001 BLUE = 4 # 0100 WHITE = 7 # 0111 As you see, WHITE is an "alias" for a value that does not exist in the Flag (0010, or 2). That seems like it's probably an error. But what about this? class FlagWithMasks(IntFlag): DEFAULT = 0x0 FIRST_MASK = 0xF FIRST_ROUND = 0x0 FIRST_CEIL = 0x1 FIRST_TRUNC = 0x2 SECOND_MASK = 0xF0 SECOND_RECALC = 0x00 SECOND_NO_RECALC = 0x10 THIRD_MASK = 0xF00 THIRD_DISCARD = 0x000 THIRD_KEEP = 0x100 Here we have three flags (FIRST_MASK, SECOND_MASK, THIRD_MASK) that are aliasing values that don't exist, but it seems intentional and not an error. So, like the enum.unique decorator that can be used when duplicate names should be an error, I'm adding a new decorator to verify that a Flag has no missing aliased values that can be used when the programmer thinks it's appropriate... but I have no idea what to call it. Any nominations? Why don't you just use the colour names from rgb.txt and their values? That's plain, simple and pretty standard. -- https://mail.python.org/mailman/listinfo/python-list
Re: imaplib: is this really so unwieldy?
On 5/28/21 2:36 AM, boB Stepp wrote: On Thu, May 27, 2021 at 6:22 PM Cameron Simpson wrote: On 27May2021 18:42, hw wrote: So it seems that IMAP support through python is virtually non-existent. This still sureprises me, but I've not tried to use IMAP seriously. I read email locally, and collect it with POP instead. With a tool I wrote myself in Python, as it happens. I am out of my league here, but what I found in one of my books might be helpful. Al Sweigart wrote a useful book, "Automate the Boring Stuff in Python". In chapter 16 he considers email. In the "IMAP" section he states: Just as SMTP is the protocol for sending email, the Internet Message Access Protocol (IMAP) specifies how to communicate with an email provider’s server to retrieve emails sent to your email address. Python comes with an imaplib module, but in fact the third-party imapclient module is easier to use. This chapter provides an introduction to using IMAPClient; the full documentation is at http://imapclient.readthedocs.org/. The imapclient module downloads emails from an IMAP server in a rather complicated format. Most likely, you’ll want to convert them from this format into simple string values. The pyzmail module does the hard job of parsing these email messages for you. You can find the complete documentation for PyzMail at http://www.magiksys.net/pyzmail/. Install imapclient and pyzmail from a Terminal window. Appendix A has steps on how to install third-party modules. In the next little section he shows how to retrieve and delete emails with IMAP using the two third-party tools mentioned above. And of course there is more. Apparently this book is now in its second edition. The first edition is available online for free. The link to chapter 16 which discusses email is: https://automatetheboringstuff.com/chapter16/ Hopefully this will prove helpful to the OP. Thanks for the pointer! I don't know which imaplib the author uses; the imaplib I found definitely doesn't give uids of the messages, contrary to the example he's giving. -- https://mail.python.org/mailman/listinfo/python-list
Re: imaplib: is this really so unwieldy?
On 5/25/21 3:55 PM, Grant Edwards wrote: On 2021-05-25, hw wrote: I'm about to do stuff with emails on an IMAP server and wrote a program using imaplib My recollection of using imaplib a few years ago is that yes, it is unweildy, oddly low-level, and rather un-Pythonic (excuse my presumption in declaring what is and isn't "Pythonic"). It's good to know that it's not me and that I simply made a bad pick for something to learn python with :) I switched to using imaplib2 and found it much easier to use. It's a higher-level wrapper for imaplib. I think this is the currently maintained fork: https://github.com/jazzband/imaplib2 I haven't activly used either for several years, so things may have changed... -- Grant -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/25/21 3:09 PM, Greg Ewing wrote: On 25/05/21 5:56 pm, Avi Gross wrote: Var = read in something from a file and make some structure like a data.frame Var = remove some columns from the above thing pointed to by Var Var = make some new calculated columns ditto Var = remove some rows ... Var = set some kind of grouping on the above or sort it and so on. As long as all the values are of the same type, this isn't too bad, although it might interfere with your ability to give the intermediate results names that help the reader understand what they refer to. A variable that refers to things of different *types* at different times is considerably more confusing, both for a human reader and for any type checking software you might want to use. How would this matter when the variables are typeless? Often times, it's not very practical to figure out the type of a value before assigning it to a variable ... How can you write a recursive function without this kind of variable shadowing? Each invocation of a function places the internal namespace in front of the parent so the meaning of a variable name used within is always backed by all the iterations before it. Um, no. What you're describing is called "dynamic scoping", and Python doesn't have it. Python is *lexically* scoped, meaning that only scopes that textually enclose the function in the source are searched for names. Frames on the call stack don't come into it. So what if you suggest we allow re-use of names but WARN you. ... The first 50 places may be in other instances of the recursive function and you have already been warned this way 49 times If this were to be done, the shadowing would be detected at compile time, so you would only be warned once. Works fine in perl (and you can have it without warnings if you want to, though that's not recommended): perl -e 'use warnings; my $shadow; my $shadow; my $shadow'; "my" variable $shadow masks earlier declaration in same scope at -e line 1. "my" variable $shadow masks earlier declaration in same scope at -e line 1. "Mask" seems like a much better word for this than "shadow" ... -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
s and even suggesting changes. I simply suggest when others push back and tell you it was designed this way for darn good reasons and many LIKE IT the way it is, ... -Original Message- From: Python-list On Behalf Of Cameron Simpson Sent: Monday, May 24, 2021 5:34 AM To: python-list@python.org Subject: Re: learning python ... On 24May2021 08:21, hw wrote: On 5/24/21 12:03 AM, Cameron Simpson wrote: On 23May2021 21:02, Stestagg wrote: On Sun, 23 May 2021 at 20:37, hw wrote: I don't know about shadowing. Shadowing is effectively saying “within this bit of code, (scope) I’m going to use an already-used name for my own value” An example might make this clearer: x = 1 # global variable def f(a): x = a * 2 return x Inside the function f() the name 'x" shadows the global "x"; references to "x" are to the function's local vairable. Which is very desireable. If it works that way, I would consider it an entirely different variable. Is there a way to access the global x from within a function without transferring it through parameters of the function? Than can also sometimes be useful. Sure. You can declare a name like this: def f(a): global x # find x in the global namespace (the module) x = a * 2 return x This is pretty rare and usually discouraged. Of there are times when it is useful. Note that in this function: x = 1 y = 2 def f(a): x = 3 print(x, y) "x" is local, because the function contains an assignment to it. "y" comes from an outer scope (in this case, the global scope) because there's no assignment to it. As Stestagg has mentioned, there are also tools called linters which warn you about issues like this. Tools like pyflakes, pylint, pycodestyle all inspect your code for a wide variety of potential errors and discouraged habits. Not to mention tools like mypy which do type validation. So you're saying one can't really go without those unless you want to take the risk? Self restraint and developing good habits does 99% of the work. Linters are great for catching various accidents. [...] I'm not saying it shouldn't be allowed to defeat or to re-define stuff, only that it shouldn't go through quietly. Well, most of us use linters to exhibit that noise, rather than requiring the code to be littered with special directives. I usually code without much linter fuss until I've got the latest batch of work (eg feature or fix) ready, commit the changes, then lint vigorously and commit that polish before merging with the main line of code. Finally, consider this code: num = input("Enter a number: ") num = int(num) input() returns a string, which would need converting to a number before some numeric stuff. Plenty of people write the above. To my mind, this is also a kind of shadowing, and I like this instead: num_s = input("Enter a number: ") num = int(num_s) where the "_s" indicates quietly that this variable holds a string. Is that shadowing to your mind? Or not? If yes, should the language emit noise there, too? Remembering that Python _values_ are strongly typed, though the variables are not (a variable might reference any kind of object, as above). I wouldn't say that your opinion would be wrong regardless of what side of this question you come down on, but Python's chosen a side: noise for nonsensical things, but not noise for dubious things. But plenty of linters to complain about dubious things. Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list -- https://mail.python.org/mailman/listinfo/python-list
Re: imaplib: is this really so unwieldy?
On 5/26/21 12:25 AM, Cameron Simpson wrote: On 25May2021 19:21, hw wrote: On 5/25/21 11:38 AM, Cameron Simpson wrote: On 25May2021 10:23, hw wrote: if status != 'OK': print('Login failed') exit Your "exit" won't do what you want. I expect this code to raise a NameError exception here (you've not defined "exit"). That _will_ abort the programme, but in a manner indicating that you're used an unknown name. You probably want: sys.exit(1) You'll need to import "sys". Oh ok, it seemed to be fine. Would it be the right way to do it with sys.exit()? Having to import another library just to end a program might not be ideal. To end a programme early, yes. (sys.exit() actually just raises a particular exception, BTW.) I usually write a distinct main function, so in that case one can just "return". After all, what seems an end-of-life circumstance in a standalone script like yours is just an "end this function" circumstance when viewed as a function, and that also lets you _call_ the main programme from some outer thing. Wouldn't want that outer thing cancelled, if it exists. My usual boilerplate for a module with a main programme looks like this: import sys .. def main(argv): ... main programme, return like any other function ... other code for the module - functions, classes etc ... if __name__ == '__main__': sys.exit(main(sys.argv)) which (a) puts main(0 up the top where it can be seen, (b) makes main() an ordinary function like any other (c) lets me just import that module elsewhere and (d) no globals - everything's local to main(). The __name__ boilerplate at the bottom is the magic which figures out if the module was imported (__name__ will be the import module name) or invoked from the command line like: python -m my_module cmd-line-args... in which case __name__ has the special value '__main__'. A historic mechanism which you will convince nobody to change. Thanks, that seems like good advice. You'd be surprised how useful it is to make almost any standalone programme a module like this - in the medium term it almost always pays off for me. Even just the discipline of shoving all the formerly-global variables in the main function brings lower-bugs benefits. What do you do with it when importing it? Do you somehow design your programs as modules in some way that makes them usable as some kind of library funktion? I've done little with IMAP. What's in msgnums here? Eg: print(type(msgnums), repr(msgnums)) just so we all know what we're dealing with here. [b''] message_uuids = [] for number in str(msgnums)[3:-2].split(): This is very strange. [...] Yes, and I don't understand it. 'print(msgnums)' prints: [b''] when there are no messages and [b'1 2 3 4 5'] Chris has addressed this. msgnums is list of the data components of the IMAP response. By going str(msgnums) you're not getting "the message numbers as text" you're getting what printing a list prints. Which is roughly Python code: the brakcets and the repr() of each list member. Well, of course I exepect to get message numbers returned from such a library function, not the raw imap response. What is the library for when I have to figure it all out by myself anyway. Notice that the example code accessed msgnums[0] - that is the first data component, a bytes. That you _can_ convert to a string (under assumptions about the encoding). And of course, I don't want to randomly convert bytes into strings ... By getting the "str" form of a list, you're forced into the weird [3:-2] hack to ttrim the ends. But it is just a hack for a transcription mistake, not a sane parse. Right, thats why I don't like it and is part of what makes it so unwieldy. So I was guessing that it might be an array containing a single a string and that refering to the first element of the array turns into a string with which split() can used. But 'print(msgnums[0].split())' prints [b'1', b'2', b'3', b'4', b'5'] msgnums[0] is bytes. You can do most str things with bytes (because that was found to be often useful) but you get bytes back from those operations as you'd hope. As someone unfamiliar with python, I was wondering what this output means. It could be items of an array that are bytes containing numbers, like, in binary, 0001, 0010, and so on. That's more like what I would expect and not something I would want to convert into a string. so I can only guess what that's supposed to mean: maybe an array of many bytes? The documentation[1] clearly says: "The message_set options to commands below is a string [...]" But that is the parameter to the _call_: your '(UID)' parameter. No, it's not a uid. With library, I haven't found a way to get uids. The function to call reqires a string, not bytes or an array of bytes. The included example contradict
Re: learning python ...
On 5/25/21 10:32 AM, Chris Angelico wrote: On Tue, May 25, 2021 at 1:00 PM hw wrote: On 5/24/21 3:54 PM, Chris Angelico wrote: You keep using that word "unfinished". I do not think it means what you think it does. What do you think I think it means? I think it means that the language is half way through development, doesn't have enough features to be usable, isn't reliable enough for production, and might at some point in the future become ready to use. Right, that is what it seemed. None of which is even slightly supported by evidence. That's not true. Remember the change from version 2 to 3 and ask yourself how likely it is that breaking things like that happens again. You may find a statement from developers about a policy that changes are to be announced a year before they go in, and that is evidence enough. What you make of this policy and what it means to you is for you to decide, but the evidence is clearly there. Python has keywords. C has keywords. In Python, "None" is a keyword, so you can't assign to it; in C, "int" is a keyword, so you can't assign to it. There is no fundamental difference here, and the two languages even have roughly the same number of keywords (35 in current versions of Python; about 40 or 50 in C, depending on the exact specification you're targeting). The only difference is that, in Python, type names aren't keywords. You're getting caught up on a trivial difference that has happened to break one particular test that you did, and that's all. Then what is 'float' in the case of isinstance() as the second parameter, and why can't python figure out what 'float' refers to in this case? Perhaps type names should be keywords to avoid confusion. It's a name. In Python, any name reference is just a name reference. There's no magic about the language "knowing" that the isinstance() function should take a keyword, especially since there's no keywords for these things. When I look at the error message, it seems to indicate that python knows very well what kind of parameter is expected. Maybe you can show how this is a likeable feature. I already understood that you can somehow re-define functions in python and I can see how that can be useful. You can do things like that in elisp as well. But easily messing up built-in variable types like that is something else. Why would I want that in a programming language, and why would I want to use one that allows it? Because all you did was mess with the *name* of the type. It's not breaking the type system at all. And how is it a likeable feature? You can complain about whether it's likeable or not, but all you're doing is demonstrating the Blub Paradox. And you remain unable to show how python making it easy to mess up type names is a likeable feature. The C language never says that Python is "unfinished". I'm not making assumptions, I'm reading your posts. I never said it is unfinished, I said it /seems/ unfinished. In any case, there is nothing insulting about it. Python is still being worked on (which is probably a good thing), and the switch from version 2 to version 3 has broken a lot of software, which doesn't help in making it appear as finished or mature. It's been around for thirty years. Quit fudding. You're getting very close to my killfile. I take it you can't stand it when someone thinks differently than you do. Good for you that you have a kill file to protect you from different thoughts and ideas. Python 3 has been around since 2009. Are you really telling me that Python looks unfinished because of a breaking change more than a decade ago? It looked unfinished to me because it doesn't even give an error message when I assign something to a type name as if it was a variable. Breaking things like that doesn't help, and it doesn't matter that it happened a while ago because I still have to deal with the issues it caused. That something has been around for a while doesn't have anything to do with how finished or unfinished it may appear. The Go language didn't even *exist* before Python 3 - does that mean that Go is also unfinished? Go is one of the games I never learned to play, though it seems kinda interesting. Just look at what the compiler says when you try to compile these examples. In the first example, you can't defeat a built-in data type by assigning something to it, and in the second one, you declare something as an instance of a build-in data type and then try to use it as a function. That is so because the language is designed as it is. Yes, because C uses keywords for types. That's the only difference you're seeing here. You keep getting caught up on this one thing, one phenomenon that comes about because of YOUR expectations that Python and C should behave the same way. If you weren't doing isinstance checks, you wouldn't even have noticed this! It is *NOT* a fundamental differe
Re: learning python ...
On 5/25/21 9:42 AM, Greg Ewing wrote: On 25/05/21 2:59 pm, hw wrote: Then what is 'float' in the case of isinstance() as the second parameter, and why can't python figure out what 'float' refers to in this case? You seem to be asking for names to be interpreted differently when they are used as parameters to certain functions. Sure, why not. Since python allows me to use the name of a variable type as a name for a variable, it could at least figure out which, the type or the variable, to use as parameter for a function that should specify a variable type when the name is given. Obviously, python knows what's expected, so why not chose that. Python doesn't do that sort of thing. The way it evaluates expressions is very simple and consistent, and that's a good thing. It means there aren't any special cases to learn and remember. Ok, that's certainly a valid point. It could be a general case that python picks for functions what is expected of their parameters when their parameters have ambigous names. Maybe you're not aware that isinstance is just a function, and not any kind of special syntax? Perhaps type names should be keywords to avoid confusion. Python has quite a lot of built-in types, some of them in the builtin namespace, some elsewhere. Making them all keywords would be impractical, even if it were desirable. And what about user-defined types? Why should they be treated differently to built-in types? Or are you suggesting there should be a special syntax for declaring type names? I don't know; how many different types does it have? Maybe a special syntax for declaring type names which then can not become ambigous so easily would be a good thing? I already wondered that the scope of variables is not limited to the context they are declared within: for number in something: # do stuff # do more stuff or not ... print(number) When you do something like that in perl, the variable you declared is out of scope outside the loop whereas python surprises me by keeping it around. Somehow, the more I learn about python, the harder it becomes for me to read. Maybe that changes over time, yet keeping variables around like that is not something I would prefer. -- https://mail.python.org/mailman/listinfo/python-list
Re: imaplib: is this really so unwieldy?
On 5/25/21 11:38 AM, Cameron Simpson wrote: On 25May2021 10:23, hw wrote: I'm about to do stuff with emails on an IMAP server and wrote a program using imaplib which, so far, gets the UIDs of the messages in the inbox: #!/usr/bin/python I'm going to assume you're using Python 3. Python 3.9.5 import imaplib import re imapsession = imaplib.IMAP4_SSL('imap.example.com', port = 993) status, data = imapsession.login('user', 'password') if status != 'OK': print('Login failed') exit Your "exit" won't do what you want. I expect this code to raise a NameError exception here (you've not defined "exit"). That _will_ abort the programme, but in a manner indicating that you're used an unknown name. You probably want: sys.exit(1) You'll need to import "sys". Oh ok, it seemed to be fine. Would it be the right way to do it with sys.exit()? Having to import another library just to end a program might not be ideal. messages = imapsession.select(mailbox = 'INBOX', readonly = True) typ, msgnums = imapsession.search(None, 'ALL') I've done little with IMAP. What's in msgnums here? Eg: print(type(msgnums), repr(msgnums)) just so we all know what we're dealing with here. [b''] message_uuids = [] for number in str(msgnums)[3:-2].split(): This is very strange. Did you see the example at the end of the module docs, it has this example code: import getpass, imaplib M = imaplib.IMAP4() M.login(getpass.getuser(), getpass.getpass()) M.select() typ, data = M.search(None, 'ALL') for num in data[0].split(): typ, data = M.fetch(num, '(RFC822)') print('Message %s\n%s\n' % (num, data[0][1])) M.close() M.logout() Yes, and I don't understand it. 'print(msgnums)' prints: [b''] when there are no messages and [b'1 2 3 4 5'] So I was guessing that it might be an array containing a single a string and that refering to the first element of the array turns into a string with which split() can used. But 'print(msgnums[0].split())' prints [b'1', b'2', b'3', b'4', b'5'] so I can only guess what that's supposed to mean: maybe an array of many bytes? The documentation[1] clearly says: "The message_set options to commands below is a string [...]" I also need to work with message uids rather than message numbers because the numbers can easily change. There doesn't seem to be a way to do that with this library in python. So it's all guesswork, and I gave up after a while and programmed what I wanted in perl. The documentation of this library sucks, and there are worlds between it and the documentation for the libraries I used with perl. That doesn't mean I don't want to understand why this is so unwieldy. It's all nice and smooth in perl. [1]: https://docs.python.org/3/library/imaplib.html It is just breaking apart data[0] into strings which were separated by whitespace in the response. And then using those same strings as keys for the .fecth() call. That doesn't seem complex, and in fact is blind to the format of the "message numbers" returned. It just takes what it is handed and uses those to fetch each message. That's not what the documentation says. status, data = imapsession.fetch(number, '(UID)') if status == 'OK': match = re.match('.*\(UID (\d+)\)', str(data)) [...] It's working (with Cyrus), but I have the feeling I'm doing it all wrong because it seems so unwieldy. IMAP's quite complex. Have you read RFC2060? https://datatracker.ietf.org/doc/html/rfc2060.html Yes, I referred to it and it didn't become any more clear in combination with the documentation of the python library. The imaplib library is probably a fairly basic wrapper for the underlying protocol which provides methods for the basic client requests and conceals the asynchronicity from the user for ease of (basic) use. Skip Montanaro seems to say that the byte problem comes from the change from python 2 to 3 and there is a better library now: https://pypi.org/project/IMAPClient/ But the documentation seems even more sparse than the one for imaplib. Is it a general thing with python that libraries are not well documented? Apparently the functions of imaplib return some kind of bytes while expecting strings as arguments, like message numbers must be strings. The documentation doesn't seem to say if message UIDs are supposed to be integers or strings. You can go a long way by pretending that they are opaque strings. That they may be numeric in content can be irrelevant to you. treat them as strings. That's what I ended up doing. So I'm forced to convert stuff from bytes to strings (which is weird because bytes are bytes) "bytes are bytes" is tautological. which is a good thing You're getting bytes for a few reasons: - the imap protocol largely talks about octets (bytes), but says they're text. For this reason a lot of stuff y
imaplib: is this really so unwieldy?
Hi, I'm about to do stuff with emails on an IMAP server and wrote a program using imaplib which, so far, gets the UIDs of the messages in the inbox: #!/usr/bin/python import imaplib import re imapsession = imaplib.IMAP4_SSL('imap.example.com', port = 993) status, data = imapsession.login('user', 'password') if status != 'OK': print('Login failed') exit messages = imapsession.select(mailbox = 'INBOX', readonly = True) typ, msgnums = imapsession.search(None, 'ALL') message_uuids = [] for number in str(msgnums)[3:-2].split(): status, data = imapsession.fetch(number, '(UID)') if status == 'OK': match = re.match('.*\(UID (\d+)\)', str(data)) message_uuids.append(match.group(1)) for uid in message_uuids: print('UID %5s' % uid) imapsession.close() imapsession.logout() It's working (with Cyrus), but I have the feeling I'm doing it all wrong because it seems so unwieldy. Apparently the functions of imaplib return some kind of bytes while expecting strings as arguments, like message numbers must be strings. The documentation doesn't seem to say if message UIDs are supposed to be integers or strings. So I'm forced to convert stuff from bytes to strings (which is weird because bytes are bytes) and to use regular expressions to extract the message-uids from what the functions return (which I shouldn't have to because when I'm asking a function to give me a uid, I expect it to return a uid). This so totally awkward and unwieldy and involves so much overhead that I must be doing this wrong. But am I? How would I do this right? -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/25/21 12:37 AM, Greg Ewing wrote: On 25/05/21 9:27 am, Cameron Simpson wrote: On 24May2021 16:17, hw wrote: > Or it doesn't forget about the old one and the old one becomes inaccessible (unless you have a reference to it, if there is such a thing in python). How do you call that? You're conflating values (objects, such as an int or a string) with variables (which _are_ references in Python, I think hw might have meant the C++ notion of a reference to a *variable*. There is no equivalent of that in Python. yes, or a reference in perl Python does have references to *objects*. All objects live on the heap and are kept alive as long as there is at least one reference to them. If you rebind a name, and it held the last reference to an object, there is no way to get that object back. Are all names references? When I pass a name as a parameter to a function, does the object the name is referring to, when altered by the function, still appear altered after the function has returned? I wouldn't expect that ... On the other hand, if you shadow a name, the original name still exists, and there is usually some way to get at it, e.g. >>> int = 42 >>> int 42 >>> __builtins__.int >>> You mean built-in objects never go away, even when they are no longer referenced? -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/24/21 4:28 PM, Michael Torrie wrote: On 5/24/21 8:17 AM, hw wrote: What does python actually do in the first example? Does it overshadow a variable or does it change one? If it overshadows a variable, it would be dubious, if it doesn't, it won't be dubious. Are you referring to this? num = input("Enter a number: ") num = int(num) yes No it is not "overshadowing" a variable. You cannot get back to the original string value for num. So the other example that uses a second variable to avoid possible ambiguity could be considered as bloating because it keeps both variables around. There are more alternatives: Python might create a new variable with the same name and forget about the old one. Or it doesn't forget about the old one and the old one becomes inaccessible (unless you have a reference to it, if there is such a thing in python). How do you call that? Python variables are not memory boxes like in a compiled language. They are names bound to objects, as Mr Simpson alluded to. That seems like an important distinction. I've always been thinking of variables that get something assigned to them, not as something that is being assigned to something. So in the first line, the name num is bound to a string. In the second line, the name is re-bound to an int object. I would think of it as assigning a string to a variable and then changing the content of the variable by assigning something else to the same variable. When variables are typeless, it doesn't matter if a string or an integer is assigned to one (which is weird but can be very useful). It seems much more practical to assign different strings to the same variable rather than assigning a different variable to each string, or to assign a string to a variable and then to assign an integer to it. Isn't that what variables are for? Furthermore, if num had come from the global name scope, either of these lines would create a local name num that does shadow the name from the global scope. Hope that helps. Yes, I guess it will be interesting not to think of variables but of objects. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/24/21 4:37 PM, Chris Angelico wrote: On Tue, May 25, 2021 at 12:31 AM Michael Torrie wrote: On 5/24/21 8:24 AM, Chris Angelico wrote: On Tue, May 25, 2021 at 12:18 AM hw wrote: There are more alternatives: Python might create a new variable with the same name and forget about the old one. Or it doesn't forget about the old one and the old one becomes inaccessible (unless you have a reference to it, if there is such a thing in python). How do you call that? It's the latter option: create a new variable, and the old one becomes inaccessible. That's called "shadowing". It's how scoping works in most languages (called "lexical scope"). Is it really shadowing, though? The old one is not only inaccessible, it's possibly reaped by the garbage collector, no? Both nums are in the same scope so the one overwrote the other in the name table. Or am I missing something. We're talking about many different things. If it's simply "num = ..." followed by "num = ...", then it's not a new variable or anything, it's simply rebinding the same name. But when you do "int = ...", it's shadowing the builtin name. Why? And how is that "shadowing"? What if I wanted to re-define the built-in thing? -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/24/21 4:41 PM, Michael Torrie wrote: On 5/24/21 8:21 AM, Michael Torrie wrote: Given your posts thus far, hw, I don't think Python is a good fit for you. You're better off learning a language that more closely aligns with the statically-typed languages you already know. Maybe it is, maybe it isn't; I've been thinking about it for a while now. That was unnecessarily harsh; my apologies. I can see now that you might be comparing some features to Perl, which is a more dynamic language. I see in your recent posts that you are trying to understand how Python works, and that is good. Hopefully you'll find Python a dynamic and useful tool. If not, that's perfectly okay. Use the right tool for the job. That's what I'm trying to do. I'm just using a particular problem I want to solve as an occassion to maybe learn python because it seems much easier to solve in python than in perl. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/24/21 3:54 PM, Chris Angelico wrote: On Mon, May 24, 2021 at 11:35 PM hw wrote: On 5/24/21 9:52 AM, Chris Angelico wrote: Does C give you a warning if you create a function-local variable called "printf"? No, and it shouldn't. Does any other language complain if you use its scoping rules to reuse a name? Nope. Does Python? As above, no. Try the equivalent of above python in C: void foo(void) { int int = 25; printf("int: %d\n", int); } int main(int argc, char **argv) { foo(); } I did specifically mention "printf", which works just fine, as you see below. see below I don't know which C compiler you're using; gcc doesn't compile this and gives several error messages. Python quietly allows things like this without any warning at all, and I'm saying that's a bad thing and that python seems unfinished because it doesn't even give a warning in cases like this. You keep using that word "unfinished". I do not think it means what you think it does. What do you think I think it means? Python has keywords. C has keywords. In Python, "None" is a keyword, so you can't assign to it; in C, "int" is a keyword, so you can't assign to it. There is no fundamental difference here, and the two languages even have roughly the same number of keywords (35 in current versions of Python; about 40 or 50 in C, depending on the exact specification you're targeting). The only difference is that, in Python, type names aren't keywords. You're getting caught up on a trivial difference that has happened to break one particular test that you did, and that's all. Then what is 'float' in the case of isinstance() as the second parameter, and why can't python figure out what 'float' refers to in this case? Perhaps type names should be keywords to avoid confusion. I don't know REXX, and I'm not sure what the equivalent would be in elisp. The issue doesn't exist in perl. It may be intentionally so that python makes it easy to defeat fundamental aspects of the language simply by, accidentially or intentionally, re-defining them without warning, and even if that is so, nobody else has to like a feature like that just because you do like it. REXX doesn't have keywords at all. (It has language syntax words, but everything is contextual, so you can quite happily say "if = 1" and then "if if" becomes valid.) Perl has keywords, just like everything else, but not for data types. This is NOT something fundamental to the language that is "defeated". You have made it harder to perform isinstance checks, but that's neither fundamental nor defeated by this shadowing. The integer type still exists - you just made a new variable with the name "int". The float type still exists - you just made a new variable with the name "float". Ok, that is an important difference. Maybe you can show how this is a likeable feature. I already understood that you can somehow re-define functions in python and I can see how that can be useful. You can do things like that in elisp as well. But easily messing up built-in variable types like that is something else. Why would I want that in a programming language, and why would I want to use one that allows it? Because all you did was mess with the *name* of the type. It's not breaking the type system at all. And how is it a likeable feature? Most Python programs manage just fine without ever doing an isinstance check, and even if you do have to, it's possible to refer to the type in other ways: (1).__class__ int = 42 isinstance(int, (1).__class__) True See? Not broken. All you did was change the meaning of the name "int", by assigning to it. No, but I take your word for it. Your claim that I'm insulting python or anoyone is ridiculous. According to your logic, C is insulting python. I suggest you stop making assumptions. The C language never says that Python is "unfinished". I'm not making assumptions, I'm reading your posts. I never said it is unfinished, I said it /seems/ unfinished. In any case, there is nothing insulting about it. Python is still being worked on (which is probably a good thing), and the switch from version 2 to version 3 has broken a lot of software, which doesn't help in making it appear as finished or mature. The example you want is probably this one: #include void foo(void) { int printf = 25; printf("int: %d\n", printf); } int main(int argc, char **argv) { foo(); } Perhaps you can't see how both examples are different because you're looking at things from a python perspective. Well, look at them from a language design perspective and tell me how different they really are. Just look at what the compiler says when you try to compile these examples. In the first example, you can't defeat a built-in data type by assigning something to it, and
Re: learning python ...
On 5/24/21 11:33 AM, Cameron Simpson wrote: On 24May2021 08:21, hw wrote: On 5/24/21 12:03 AM, Cameron Simpson wrote: On 23May2021 21:02, Stestagg wrote: On Sun, 23 May 2021 at 20:37, hw wrote: I don't know about shadowing. Shadowing is effectively saying “within this bit of code, (scope) I’m going to use an already-used name for my own value” An example might make this clearer: x = 1 # global variable def f(a): x = a * 2 return x Inside the function f() the name 'x" shadows the global "x"; references to "x" are to the function's local vairable. Which is very desireable. If it works that way, I would consider it an entirely different variable. Is there a way to access the global x from within a function without transferring it through parameters of the function? Than can also sometimes be useful. Sure. You can declare a name like this: def f(a): global x # find x in the global namespace (the module) x = a * 2 return x This is pretty rare and usually discouraged. Of there are times when it is useful. Note that in this function: x = 1 y = 2 def f(a): x = 3 print(x, y) "x" is local, because the function contains an assignment to it. "y" comes from an outer scope (in this case, the global scope) because there's no assignment to it. Thanks! That basically works the same as in perl then. As Stestagg has mentioned, there are also tools called linters which warn you about issues like this. Tools like pyflakes, pylint, pycodestyle all inspect your code for a wide variety of potential errors and discouraged habits. Not to mention tools like mypy which do type validation. So you're saying one can't really go without those unless you want to take the risk? Self restraint and developing good habits does 99% of the work. Linters are great for catching various accidents. I never needed one before. [...] I'm not saying it shouldn't be allowed to defeat or to re-define stuff, only that it shouldn't go through quietly. Well, most of us use linters to exhibit that noise, rather than requiring the code to be littered with special directives. I usually code without much linter fuss until I've got the latest batch of work (eg feature or fix) ready, commit the changes, then lint vigorously and commit that polish before merging with the main line of code. Maybe python requires a different approach than other languages in that it doesn't allow for the overhead that can be used to make things easy to read and without guessing in other languages. That overhead can be a disadvantage, yet getting to used to not having it could take a while. Finally, consider this code: num = input("Enter a number: ") num = int(num) input() returns a string, which would need converting to a number before some numeric stuff. Plenty of people write the above. To my mind, this is also a kind of shadowing, and I like this instead: num_s = input("Enter a number: ") num = int(num_s) where the "_s" indicates quietly that this variable holds a string. Isn't that a kind of overhead python is trying to avoid? Is that shadowing to your mind? Or not? If yes, should the language emit noise there, too? Remembering that Python _values_ are strongly typed, though the variables are not (a variable might reference any kind of object, as above). No, I don't see any shadowing in either example. In the first one, you (seem to) make sure that you get an integer (not considering what happens when the input is not something that can be cast into an integer) using the same variable by altering its contents. In the second example, you're using two different variables, trying to cast the first one to an integer while assigning it to a second one which is implicitly declared. If anything, I could argue that this is convoluted code because you're doing lots of stuff implicitly --- and that could be argued for both examples. You could make it worse like if(int(num = input("foo: ")) == 5): pass involving side effects, but I don't know if python would allow you to do that. (Not that I would want to do something like this, but it would make sense to me if it could be done ...) I wouldn't say that your opinion would be wrong regardless of what side of this question you come down on, but Python's chosen a side: noise for nonsensical things, but not noise for dubious things. But plenty of linters to complain about dubious things. What does python actually do in the first example? Does it overshadow a variable or does it change one? If it overshadows a variable, it would be dubious, if it doesn't, it won't be dubious. There are more alternatives: Python might create a new variable with the same name and forget about the old one. Or it doesn't forget about the old one and the old one becomes
Re: learning python ...
On 5/24/21 9:52 AM, Chris Angelico wrote: On Mon, May 24, 2021 at 3:25 PM hw wrote: On 5/23/21 10:02 PM, Stestagg wrote: On Sun, 23 May 2021 at 20:37, hw mailto:h...@adminart.net>> wrote: On 5/23/21 7:28 PM, Peter Otten wrote: > On 23/05/2021 06:37, hw wrote: >> >> Hi, >> >> I'm starting to learn python and have made a little example program >> following a tutorial[1] I'm attaching. >> >> Running it, I'm getting: >> >> >> Traceback (most recent call last): >>File "[...]/hworld.py", line 18, in >> print(isinstance(int, float)) >> TypeError: isinstance() arg 2 must be a type or tuple of types >> >> >> I would understand to get an error message in line 5 but not in 18. >> Is this a bug or a feature? > > It is a bug in your code (which you don't provide). Did you assign some > value to float, e. g.: > > >>> float = 42.0 > >>> isinstance(int, float) > Traceback (most recent call last): >File "", line 1, in > isinstance(int, float) > TypeError: isinstance() arg 2 must be a type or tuple of types > > If you do not shadow the built-in you should get > > >>> isinstance(int, float) > False > Apparently the attachment was stripped from my message. I'll put a smaller version directly into this message instead of an attachment: #!/usr/bin/python print("world!") int = 17 print("world", int) float = 6.670 print("world", float) foo = 0 print(type(int)) print(type(float)) print(type(foo)) print(isinstance(foo, str)) print(isinstance(int, float)) print(isinstance(float, float)) I don't know about shadowing. Shadowing is effectively saying “within this bit of code, (scope) I’m going to use an already-used name for my own value” That should give at least a warning. No, it shouldn't, because it's a deliberate feature. The entire point of scoping rules - whether you're in C, Python, REXX, or any other language - is to *allow* you to use a name for what you intend it to be. Does C give you a warning if you create a function-local variable called "printf"? No, and it shouldn't. Does any other language complain if you use its scoping rules to reuse a name? Nope. Does Python? As above, no. Try the equivalent of above python in C: void foo(void) { int int = 25; printf("int: %d\n", int); } int main(int argc, char **argv) { foo(); } I don't know which C compiler you're using; gcc doesn't compile this and gives several error messages. Python quietly allows things like this without any warning at all, and I'm saying that's a bad thing and that python seems unfinished because it doesn't even give a warning in cases like this. I don't know REXX, and I'm not sure what the equivalent would be in elisp. The issue doesn't exist in perl. It may be intentionally so that python makes it easy to defeat fundamental aspects of the language simply by, accidentially or intentionally, re-defining them without warning, and even if that is so, nobody else has to like a feature like that just because you do like it. Maybe you can show how this is a likeable feature. I already understood that you can somehow re-define functions in python and I can see how that can be useful. You can do things like that in elisp as well. But easily messing up built-in variable types like that is something else. Why would I want that in a programming language, and why would I want to use one that allows it? Your claim that I'm insulting python or anoyone is ridiculous. According to your logic, C is insulting python. I suggest you stop making assumptions. The example you want is probably this one: #include void foo(void) { int printf = 25; printf("int: %d\n", printf); } int main(int argc, char **argv) { foo(); } Perhaps you can't see how both examples are different because you're looking at things from a python perspective. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/24/21 12:03 AM, Cameron Simpson wrote: On 23May2021 21:02, Stestagg wrote: On Sun, 23 May 2021 at 20:37, hw wrote: I don't know about shadowing. Shadowing is effectively saying “within this bit of code, (scope) I’m going to use an already-used name for my own value” An example might make this clearer: x = 1 # global variable def f(a): x = a * 2 return x Inside the function f() the name 'x" shadows the global "x"; references to "x" are to the function's local vairable. Which is very desireable. If it works that way, I would consider it an entirely different variable. Is there a way to access the global x from within a function without transferring it through parameters of the function? Than can also sometimes be useful. If I have defeated a whole variable type by naming a variable like a variable type, I would think it is a bad idea for python to allow this without warning. There are some reasons why allowing this is quite nice. And there’s actually a ton of corner cases to consider when thinking about changing the rules As Stestagg has mentioned, there are also tools called linters which warn you about issues like this. Tools like pyflakes, pylint, pycodestyle all inspect your code for a wide variety of potential errors and discouraged habits. Not to mention tools like mypy which do type validation. So you're saying one can't really go without those unless you want to take the risk? Interestingly python 3 made this a little bit better by stopping you from rebinding (shadowing) a number of built ins, such as True and False. In your case, I agree that it is super confusing. One thing to learn to look out for is if you assign to line 9, in print(type(str)) TypeError: 'int' object is not callablea name, then use that name on a different context, expecting it to be different, then that’s not likely to work as you expect. It seems like a recipie for creating chaos. The runtime lets you do all sorts of things. Linters and type checkers exist to help you notice if you're writing such a recipe. There _are_ times when it is useful to shadow a builtin name. Not being able to prevents a useful activity. A common example in my own code is this: from cs.upd import Upd, print which shadows the print() builtin. The Upd class maintains status lines such as progress bars and so forth. It provides a print() function which withdraws the status lines, runs the builtin print, then restores them, allowing normal idiomatic use of print() in scripts making use of the status lines. Similar situations abound. I'm not saying it shouldn't be allowed to defeat or to re-define stuff, only that it shouldn't go through quietly. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
PS: On 5/24/21 7:20 AM, hw wrote: There is even no indication from the output from the program before it aborts with an error message that something might be wrong: For 'type(float)', it prints "" just like it does for int. How is anyone supposed to debug stuff like that? Ok, it prints "" for type(str) when str hasn't been defeated. But still: #!/usr/bin/python foo = 0 print(type(int)) print(type(float)) print(type(foo)) print(type(str)) type = 4 print(type(str)) line 9, in print(type(str)) TypeError: 'int' object is not callable How is this /not/ bad? It seems like a no-go for any programming language that isn't designed for the programmer to shoot into thier own feet. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/23/21 10:02 PM, Stestagg wrote: On Sun, 23 May 2021 at 20:37, hw <mailto:h...@adminart.net>> wrote: On 5/23/21 7:28 PM, Peter Otten wrote: > On 23/05/2021 06:37, hw wrote: >> >> Hi, >> >> I'm starting to learn python and have made a little example program >> following a tutorial[1] I'm attaching. >> >> Running it, I'm getting: >> >> >> Traceback (most recent call last): >> File "[...]/hworld.py", line 18, in >> print(isinstance(int, float)) >> TypeError: isinstance() arg 2 must be a type or tuple of types >> >> >> I would understand to get an error message in line 5 but not in 18. >> Is this a bug or a feature? > > It is a bug in your code (which you don't provide). Did you assign some > value to float, e. g.: > > >>> float = 42.0 > >>> isinstance(int, float) > Traceback (most recent call last): > File "", line 1, in > isinstance(int, float) > TypeError: isinstance() arg 2 must be a type or tuple of types > > If you do not shadow the built-in you should get > > >>> isinstance(int, float) > False > Apparently the attachment was stripped from my message. I'll put a smaller version directly into this message instead of an attachment: #!/usr/bin/python print("world!") int = 17 print("world", int) float = 6.670 print("world", float) foo = 0 print(type(int)) print(type(float)) print(type(foo)) print(isinstance(foo, str)) print(isinstance(int, float)) print(isinstance(float, float)) I don't know about shadowing. Shadowing is effectively saying “within this bit of code, (scope) I’m going to use an already-used name for my own value” That should give at least a warning. If I have defeated a whole variable type by naming a variable like a variable type, I would think it is a bad idea for python to allow this without warning. There are some reasons why allowing this is quite nice. And there’s actually a ton of corner cases to consider when thinking about changing the rules Perl has a way to turn off unwanted warnings. It won't change the rules to give a warning. Interestingly python 3 made this a little bit better by stopping you from rebinding (shadowing) a number of built ins, such as True and False. In your case, I agree that it is super confusing. It seems dangerous and seems to show that python is too unfinished to be used. For all I know, it makes it easy to, for example, drop a whole table in a database because something was shadowed without warning. I can imagine that there can be all kinds of situations in which something like that happens, and you can spend hours or days trying to figure out what's wrong and may never find it. One thing to learn to look out for is if you assign to a name, then use that name on a different context, expecting it to be different, then that’s not likely to work as you expect. Then why doesn't give it at least a warning? There is even no indication from the output from the program before it aborts with an error message that something might be wrong: For 'type(float)', it prints "" just like it does for int. How is anyone supposed to debug stuff like that? Why doesn't print(type(float)) give an error message after the variable type was already defeated (or prints something else)? What is it actually printing? It seems like a recipie for creating chaos. Luckily almost every python code checker and/or linter will highlight this for you. If you’re learning python, I’d highly recommend doing so in an ide or editor that has a code checker running. Emcas highlights the syntax fine; I don't know if it can do more for python. It shouldn't need to. Things get creepy when a programming language makes it so that the programmer can't figure out anymore how a result produced by his program has come about. -- https://mail.python.org/mailman/listinfo/python-list
Re: learning python ...
On 5/23/21 7:28 PM, Peter Otten wrote: On 23/05/2021 06:37, hw wrote: Hi, I'm starting to learn python and have made a little example program following a tutorial[1] I'm attaching. Running it, I'm getting: Traceback (most recent call last): File "[...]/hworld.py", line 18, in print(isinstance(int, float)) TypeError: isinstance() arg 2 must be a type or tuple of types I would understand to get an error message in line 5 but not in 18. Is this a bug or a feature? It is a bug in your code (which you don't provide). Did you assign some value to float, e. g.: >>> float = 42.0 >>> isinstance(int, float) Traceback (most recent call last): File "", line 1, in isinstance(int, float) TypeError: isinstance() arg 2 must be a type or tuple of types If you do not shadow the built-in you should get >>> isinstance(int, float) False Apparently the attachment was stripped from my message. I'll put a smaller version directly into this message instead of an attachment: #!/usr/bin/python print("world!") int = 17 print("world", int) float = 6.670 print("world", float) foo = 0 print(type(int)) print(type(float)) print(type(foo)) print(isinstance(foo, str)) print(isinstance(int, float)) print(isinstance(float, float)) I don't know about shadowing. If I have defeated a whole variable type by naming a variable like a variable type, I would think it is a bad idea for python to allow this without warning. It seems like a recipie for creating chaos. -- https://mail.python.org/mailman/listinfo/python-list
learning python ...
Hi, I'm starting to learn python and have made a little example program following a tutorial[1] I'm attaching. Running it, I'm getting: Traceback (most recent call last): File "[...]/hworld.py", line 18, in print(isinstance(int, float)) TypeError: isinstance() arg 2 must be a type or tuple of types I would understand to get an error message in line 5 but not in 18. Is this a bug or a feature? [1]: https://www.learnpython.org/en/Variables_and_Types -- https://mail.python.org/mailman/listinfo/python-list
[issue37091] subprocess - uncaught PermissionError in send_signal can cause hang
New submission from hw <13hu...@gmail.com>: Python 3.7.3 Ubuntu 18.10 Cosmic https://github.com/python/cpython/pull/13669 Encountered a condition where uncaught PermissionError caused a hang running a subprocess command with sudo -u Traceback (most recent call last): File "/usr/lib/python3.7/subprocess.py", line 474, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/lib/python3.7/subprocess.py", line 939, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/lib/python3.7/subprocess.py", line 1707, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/lib/python3.7/subprocess.py", line 990, in wait return self._wait(timeout=timeout) File "/usr/lib/python3.7/subprocess.py", line 1616, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['sudo', '-u', 'chrome', '/snap/bin/chromium', '--headless', '--disable-gpu', '--hide-scrollbars', '--ignore-certificate-errors', '--enable-sandbox', '--incognito', '--mute-audio', '--disable-databases', '--enable-strict-powerful-feature-restrictions', '--no-pings', '--no-referrers', '--timeout=3', '--window-size=1280,1000', '--screenshot=[REDACTED]_screenshot.png', 'https://[REDACTED]']' timed out after 59.9998986274004 seconds During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/lib/python3.7/subprocess.py", line 476, in run process.kill() File "/usr/lib/python3.7/subprocess.py", line 1756, in kill self.send_signal(signal.SIGKILL) File "/usr/lib/python3.7/subprocess.py", line 1746, in send_signal os.kill(self.pid, sig) PermissionError: [Errno 1] Operation not permitted -- components: Library (Lib) messages: 343939 nosy: Hw priority: normal pull_requests: 13558 severity: normal status: open title: subprocess - uncaught PermissionError in send_signal can cause hang type: behavior versions: Python 3.7 ___ Python tracker <https://bugs.python.org/issue37091> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue31578] Unexpected Floating Point Division Result
New submission from hw: To reproduce: >>> 480/1000/13.0 Actual result: 0.0 Expected result: 0.03692307692307692 Adding the zero decimal to any other combinations of the numbers produces the expected floating point result. Working as expected in Python 3 -- components: Interpreter Core messages: 302966 nosy: Hw priority: normal severity: normal status: open title: Unexpected Floating Point Division Result type: behavior versions: Python 2.7 ___ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue31578> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com