Re: Incomplete sys.path with embeddable python (Windows)!?

2023-04-22 Thread Ralf M.

Am 21.04.2023 um 18:07 schrieb Thomas Passin:

On 4/20/2023 5:47 PM, Ralf M. wrote:

Hello,

when I run a script with a "normally" installed python, the directory 
the script resides in is automatically added as first element to 
sys.path, so that "import my_local_module" finds my_local_module.py in 
the directory of the script.


However, when I run the same script with embeddable python ("Windows 
embeddable package (64-bit)", download link

https://www.python.org/ftp/python/3.11.3/python-3.11.3-embed-amd64.zip) the script 
directory is *not* prepended to the path, thus "import my_local_module" gives 
an ImportError.

I couldn't find an option to get the "normal" behaviour. Any ideas how 
to do that?


What I tried so far:
[...]
* I can add the following lines to every script:
 import sys
 script_path = __file__.rsplit("\\", 1)[0]
 if script_path not in sys.path:
 sys.path[0:0] = [script_path]
 import my_local_modul
[...] 


Thank your for your hints.

I haven't worked with embeddable python, but here are some possibilities 
that came to mind, depending on how your system works -


1. If your script is started from the command line, sys.argv[0] gives 
the path to the script; 
I didn't think of sys.argv[0] to get at the path; this might be quite 
useful, I'll try it out next week.


You could use os.path.dirname() to get its 
directory.  This will end up the same place as your code fragment, but 
looks nicer and handles different path separators (e.g., Linux vs Windows);
Yes, but it requires another import and the embedded package is only 
available for windows anyway, I think. I'll consider the idea, though.


2. You could write a little module that figures out the script's path 
and import that first in all your scripts.


3. If you know all the directories that your scripts will be in, you 
could add them all to a xx.pth file (do a search to make sure where to 
put .pth files for an embeddable case).
I thought about that, but for that to work all local modules across all 
script locations must have unique names, otherwise import might get hold 
of a module from the wrong directory. Certainly doable for a few 
scripts, but might become a source of hard to track errors when the 
number of scripts increases and later maintainers are not aware of the 
naming restriction.



[...}


--
https://mail.python.org/mailman/listinfo/python-list


Re: Incomplete sys.path with embeddable python (Windows)!?

2023-04-22 Thread Ralf M.

Am 22.04.2023 um 03:27 schrieb Greg Ewing via Python-list:

How are you invoking your script? Presumably you have some code
in your embedding application that takes a script path and runs
it. Instead of putting the code to update sys.path into every
script, the embedding application could do it before running
the script.


In principle a good idea, but I don't know how to do that:
The script is currently invoked by a .cmd file, but that may change to a 
shortcut (.lnk). This is what the embeddable package documentation calls 
"Python Application - simple approach".

To update sys.path on start up I would need to do something like
  C:\path\to\python.exe --add-path C:\s-path C:\s-path\script.py
but I couldn't find an option like --add-path.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Incomplete sys.path with embeddable python (Windows)!?

2023-04-22 Thread Ralf M.

Am 21.04.2023 um 17:31 schrieb Mats Wichmann:

On 4/20/23 15:47, Ralf M. wrote:

Hello,

when I run a script with a "normally" installed python, the directory 
the script resides in is automatically added as first element to 
sys.path, so that "import my_local_module" finds my_local_module.py in 
the directory of the script.


However, when I run the same script with embeddable python ("Windows 
embeddable package (64-bit)", download link

https://www.python.org/ftp/python/3.11.3/python-3.11.3-embed-amd64.zip) the script 
directory is *not* prepended to the path, thus "import my_local_module" gives 
an ImportError.


This is intended behavior - the question comes up from time to time. The 
embeddable distribution is intended to be part of an application, not a 
general-purpose Python you can call for just anything.


There are a bunch of details here, for example:

https://github.com/python/cpython/issues/79022

Thank you for the pointer to the issue. I'll try to remove the ._pth 
completely (and see whether that breaks anything) and may have a look at 
the nuget.org package.


I can see that for many cases the behaviour is appropriate, but I had 
hoped that there is a configuration option for the cases where it is not.


About my use case:
There is a complex application package, consisting of some commercial 
and some freeware software, tied together with scripts in at least four 
different scripting languages. Now I intend to add further functionality 
in a fifth language, Python. The idea is to make the embeddedable 
package part of the application package and have scripts for the new 
functions. Several independent functions are to be added, each 
consisting of a script plus some local modules, and all of them should 
use the same python embedded into the application package.

--
https://mail.python.org/mailman/listinfo/python-list


Incomplete sys.path with embeddable python (Windows)!?

2023-04-21 Thread Ralf M.

Hello,

when I run a script with a "normally" installed python, the directory 
the script resides in is automatically added as first element to 
sys.path, so that "import my_local_module" finds my_local_module.py in 
the directory of the script.


However, when I run the same script with embeddable python ("Windows 
embeddable package (64-bit)", download link
https://www.python.org/ftp/python/3.11.3/python-3.11.3-embed-amd64.zip) 
the script directory is *not* prepended to the path, thus "import 
my_local_module" gives an ImportError.


I couldn't find an option to get the "normal" behaviour. Any ideas how 
to do that?


What I tried so far:

* The start-up value for sys.path seems to be defined in python311._pth. 
It looks that I can add further static paths to it, but I don't know how 
to make it add the script path (which can be different for different 
scripts).


* Uncommenting "import site" in python311._pth doesn't help.

* It seems that I could import something else in python311._pth, but I 
don't know how something imported from there could find out the path of 
the script that is about to be started.


* I read the (rather short) documentation of the embeddable package and 
of the site module several times but couldn't recognize a hint as to how 
to solve the issue.


* I can add the following lines to every script:
import sys
script_path = __file__.rsplit("\\", 1)[0]
if script_path not in sys.path:
sys.path[0:0] = [script_path]
import my_local_modul
That works, but it's ugly, executing code between imports is frowned 
upon, and it needs to be added to every script.


Does anybody have a better idea?
Any help is appreciated.

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Ralf M.

Am 17.09.2022 um 00:35 schrieb Dan Stromberg:



On Fri, Sep 16, 2022 at 2:06 PM Ralf M. <mailto:ral...@t-online.de>> wrote:


I would like to replace a method of an instance, but don't know how to
do it properly.


You appear to have a good answer, but...  are you sure this is a good idea?


It's definitely a dirty hack.

It'll probably be confusing to future maintainers of this code, and I 
doubt static analyzers will like it either.


I agree that I will have to add sufficient comments for the future
maintainer, should there ever be one (and even for me to still
understand it next year). I don't use static analyzers.

I'm not the biggest fan of inheritance you'll ever meet, but maybe this 
is a good place for it?


Using a derived version of the class in question to overwrite the
method was my first idea, however I don't instantiate the class in
question myself, it is instantiated during the initialisation of
another class, so I would at least have to derive a modified version of
that as well. And that code is rather complex, with metaclasses and
custom decorators, and I feel uncomfortable messing with that, while
the method I intend to change is quite simple and straightforward.

In case anybody is interested what I'm trying to achieve:

It's simple in pandas to read an excel file into a dataframe, but only
the cell value is read. Sometimes I need more / other information, e.g.
some formatting or the hyperlink in a cell. Reopening the file with
openpyxl and getting the info is possible, but cumbersome.
Looking into the pandas code for reading excel files (which uses
openpyxl internally) I noticed a method (of an internal pandas class)
that extracts the value from an openpyxl cell. This method is rather
simple and seems the ideal spot to change to get what I want.

My idea is to instantiate pandas.ExcelFile (official pandas API), get
the reader instance (an attribute of the ExcelFile object) and modify
the method of the reader instance.

The fact that the method I change and the ExcelFile attribute containing
the reader are both private (start with _) doesn't make it any better,
but I'm desperate enough to be willing to adapt my code to every major
pandas release, if necessary.

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Ralf M.

Am 16.09.2022 um 23:34 schrieb Eryk Sun:

On 9/16/22, Ralf M.  wrote:

I would like to replace a method of an instance, but don't know how to
do it properly.


A function is a descriptor that binds to any object as a method. For example:

 >>> f = lambda self, x: self + x
 >>> o = 42
 >>> m = f.__get__(o)
 >>> type(m)
 
 >>> m.__self__ is o
 True
 >>> m(10)
 52


Thank you and Chris A. for the two suggestions how to replace a method.

I tried both
  inst.method = functools.partial(new_method, inst)
and
  inst.method = new_method.__get__(inst)
and both work in my toy example.
I will try it on the real code next week.

Even though the functools.partial solution is easier to understand (at
least for me), I will probably use the __get__ solution as it avoids
the import of an extra library.

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


How to replace an instance method?

2022-09-16 Thread Ralf M.
I would like to replace a method of an instance, but don't know how to 
do it properly.


My first naive idea was

inst = SomeClass()
def new_method(self, param):
# do something
return whatever
inst.method = new_method

however that doesn't work: self isn't passed as first parameter to
the new inst.method, instead inst.method behaves like a static method.

I had a closer look at the decorators classmethod and staticmethod.
Unfortunetely I couldn't find a decorator / function "instancemethod"
that turns a normal function into an instancemethod.

The classmethod documentation contains a reference to the standard
type hierarchie, and there is an explanation that an instancemethod
is sort of a dynamically created wrapper around a function, which
is accessable as __func__.
So I modified the last line of the example above to

inst.method.__func__ = new_method

but got told that __func__ is read only.

I found some information about methods in the Descriptor HowTo Guide,
but it's about how it works internally and doesn't tell how to solve
my problem (at least it doesn't tell me).

Now I'm running out of ideas what to try next or what sections of the
documentation to read next.

Any ideas / pointers?

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


Re: .0 in name

2022-05-28 Thread Ralf M.

Am 13.05.2022 um 23:23 schrieb Paul Bryan:

On Sat, 2022-05-14 at 00:47 +0800, bryangan41 wrote:


May I know (1) why can the name start with a number?


The name of an attribute must be an identifier. An identifier cannot
begin with a decimal number.


I'm not sure about the first statement. Feeding

[print("locals:", locals()) or c for c in "ab"]

to the REPL, the result is

locals: {'.0': , 'c': 'a'}
locals: {'.0': , 'c': 'b'}
['a', 'b']

i.e. there is a variable of name .0 in the local namespace within the 
list comprehension, and .0 is definitely not an identifier.


I came across this while investigating another problem with list 
comprehensions, and I think the original post was about list comprehensions.


There also can be non-identifier names in the global namespace and as 
attributes, e.g. using the REPL again:


globals()["42"] = "The Answer"
globals()

outputs (see last entry)

{'__name__': '__main__', '__doc__': None, '__package__': None, 
'__loader__': , '__spec__': 
None, '__annotations__': {}, '__builtins__': (built-in)>, '42': 'The Answer'}


and

class Cls:
def __init__(self, lst):
for i, e in enumerate(lst):
self.__dict__[str(i)] = e

obj = Cls([31, 42, 53])
getattr(obj, "1")

works and outputs

42


(2) where in the doc is it?!


https://docs.python.org/3/reference/lexical_analysis.html#identifiers


That refers to identifiers, i.e. names that are recognised as such by 
the lexer, i.e. that can be written directly in Python source code.


As shown above, names that are not identifiers can be used in several 
namespaces and as attributes. It's just a bit harder to use 
non-identifier names than identifiers.

Whether it's a good idea to use them at all is a different question.

I think the OP wondered about the .0 in the local namespace within list 
comprehensions. Unfortunately I cannot say much about that.



Paul


Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


Re: "py.ini" question

2021-04-25 Thread Ralf M.

Am 25.04.2021 um 16:30 schrieb Mats Wichmann:


On 4/24/21 2:57 PM, Chris Angelico wrote:
On Sun, Apr 25, 2021 at 5:57 AM Gisle Vanem  
wrote:


With 'py -3.6' or 'py 3.8' I get the expected.
But with 'py -3':
    Python 3.8.9 (default, Apr 13 2021, 15:54:59)  [GCC 10.2.0 64 bit 
(AMD64)] on win32


I believe that's because you're asking for "the latest in the 3.x 
series".


unless differently described by the ini file, which is what the OP is 
trying to do.


I just added a 3.10 alpha to my Windows setup (I don't do my programming 
there, so there hadn't been any need), and set up an ini file to leave 
3.9 as the default and all works as expected - py -0, py, py -3, py 
-3.10 all given me the one I would expect to get based on that setup (-0 
shows 3.9-64 starred, despite 3.10-64 being "the latest).


Personally stumped why it's not working for Gisle.


I think the problem / misunderstanding is that Gisle put in py.ini only
 [defaults]
 python=3.6

and expected this to make py -3 start 3.6. However py -3 looks for a key 
named 'python3' and, not finding it, uses default behaviour (ignoring 
the 'python' key), i.e. starts the most modern stable 3.x.


The py.ini documentation is a bit hard to find in the help file and hard 
to understand as the interesting part talks about environment variables 
and shebang line commands, not py.ini settings and py.exe parameters. 
However, the behaviour is the same in both cases and the relevant 
example is:


"If PY_PYTHON=3.1-32, the command python will use the 32-bit 
implementation of 3.1 whereas the command python3 will use the latest 
installed Python (PY_PYTHON was not considered at all as a major version 
was specified.)"


I tried the (rather insane) py.ini
 [defaults]
 python=3.7
 python2=3.8
 python4=2.7
and it works as documented (py -3 shows default behaviour as there is no 
'python3' in py.ini):


C:\>py
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 
64 bit(AMD64)] on win32

C:\>py -2
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 
bit (AMD64)] on win32

C:\>py -3
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 
bit (AMD64)] on win32

C:\>py -4
Python 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:19:08) [MSC v.1500 32 
bit (Intel)] on win32





--
https://mail.python.org/mailman/listinfo/python-list


unittest test discovery: regular packages vs. namespace packages

2020-07-10 Thread Ralf M.

Hello,

to my last question I got many helpful and enlightening answers.
So I try again with a completely different topic.

https://docs.python.org/3/library/unittest.html#test-discovery
says about test discovery:

"Unittest supports simple test discovery. In order to be compatible with 
test discovery, all of the test files must be modules or packages 
(including namespace packages) importable from the top-level directory 
of the project (this means that their filenames must be valid identifiers).

[...]
Note: As a shortcut, python -m unittest is the equivalent of python -m 
unittest discover."


Therefore I expected
python -m unittest
to run all tests in the current directory and its subdirectories, 
regardless of whether the subdirectories contain a __init__.py or not.


However, this only works for me if an (empty) __init__.py is present, 
i.e. the package is a regular one. As soon as I delete the __init__.py, 
turning the regular package into a namespace package, unittest doesn't 
find the test files any more. When I recreate __init__.py, the test file 
(e.g. test_demo.py) is found again. See demo session further down.


I tried the following Python versions, all showed the same behavior:
 Python 3.7.1 (python.org) on Win10
 Python 3.7.4 (python.org) on Win7
 Python 3.7.7 (Anaconda) on Win10
 Python 3.8.3 (Anaconda) on Win10

What am I missing / misunderstanding?


Demo session:

F:\demo>dir /s /b
F:\demo\test_we4n7uke5vx
F:\demo\test_we4n7uke5vx\test_demo.py
F:\demo\test_we4n7uke5vx\__init__.py

F:\demo>type test_we4n7uke5vx\__init__.py

F:\demo>type test_we4n7uke5vx\test_demo.py
import unittest
class SomeTestCase(unittest.TestCase):
def test_fail_always(self):
self.assertTrue(False)

F:\demo>py -m unittest
F
==
FAIL: test_fail_always (test_we4n7uke5vx.test_demo.SomeTestCase)
--
Traceback (most recent call last):
  File "F:\demo\test_we4n7uke5vx\test_demo.py", line 4, in test_fail_always
self.assertTrue(False)
AssertionError: False is not true

--
Ran 1 test in 0.001s

FAILED (failures=1)

F:\demo>del test_we4n7uke5vx\__init__.py

F:\demo>py -m unittest

--
Ran 0 tests in 0.000s

OK

F:\demo>echo # > test_we4n7uke5vx\__init__.py

F:\demo>py -m unittest
F
==
FAIL: test_fail_always (test_we4n7uke5vx.test_demo.SomeTestCase)
--
Traceback (most recent call last):
  File "F:\demo\test_we4n7uke5vx\test_demo.py", line 4, in test_fail_always
self.assertTrue(False)
AssertionError: False is not true

--
Ran 1 test in 0.001s

FAILED (failures=1)

F:\demo>
--
https://mail.python.org/mailman/listinfo/python-list


Enums are Singletons - but not always?

2020-05-23 Thread Ralf M.

Hello,

recently I wrote a small library that uses an Enum. That worked as 
expected. Then I added a main() and if __name__ == "__main__" to make it 
runable as script. Now Enum members that should be the same aren't 
identical any more, there seem to be two instances of the same Enum.


I think I know what's going on, but cannot find a good and elegant way 
to avoid the problem. I hope someone here can help me there.


Below are a simplified code sample, the results when I run it and my 
thoughts.


# Code of mod1.py #
import enum, mod2
class En(enum.Enum):
A = 1
B = 2
def main():
a = mod2.getA()
print("a is En.A:", a is En.A)
print("a:", repr(a), "En.A:", repr(En.A))
print("id(a), id(a.__class__)", id(a), id(a.__class__))
print("id(En.A), id(En)  ", id(En.A), id(En))
if __name__ == "__main__":
main()
# End of mod1.py #

# Code of mod2.py #
import mod1
def getA():
return mod1.En.A
# End of mod2.py #

# Results when run: #
C:\tmp>py mod1.py
a is En.A: False
a:  En.A: 
id(a), id(a.__class__) 33305864 7182808
id(En.A), id(En)   33180552 7183752

C:\tmp>py
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 
64 bit

(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod1
>>> mod1.main()
a is En.A: True
a:  En.A: 
id(a), id(a.__class__) 49566792 44574280
id(En.A), id(En)   49566792 44574280
>>>

So: When run as script there are two instances of En (different ids), 
but when mod1 is imported and mod1.main() is run it works as expected 
(just one instance of En, same ids).

BTW: py -m mod1 doesn't work either.

What I thing is happening:
When the script is run, mod1.py is executed and an instance of En and 
its members is created. During the same run mod1 is also imported (via 
mod2), the file mod1.py is executed again as part of the import and 
another, different instance of En and its members is created.


How do I have to change mod1.py to avoid the problem?
Currently I have moved main() into a new file script.py. That works, but 
is not what I wanted.


I doubt it's a bug in the enum module, but should that be the case, I'm 
willing to open an issue on the bug tracker.


Or can nothing be done about it?

Looking forward to any ideas
Ralf M.

P.S.:
As I was about to send this post the following modification occured to 
me (see below). It works, but it doesn't feel right to import a module 
directly from inside itself.

# Modified code of mod1.py (one line added) #
import enum, mod2
class En(enum.Enum):
A = 1
B = 2
from mod1 import En  # NEW LINE, overwrite just defined En
def main():
a = mod2.getA()
print("a is En.A:", a is En.A)
print("a:", repr(a), "En.A:", repr(En.A))
print("id(a), id(a.__class__)", id(a), id(a.__class__))
print("id(En.A), id(En)  ", id(En.A), id(En))
if __name__ == "__main__":
main()
--
https://mail.python.org/mailman/listinfo/python-list


Re: Spread a statement over various lines

2019-09-19 Thread Ralf M.

Am 18.09.2019 um 22:24 schrieb Alexandre Brault:


On 2019-09-18 4:01 p.m., Ralf M. wrote:


I don't know the exact rules of Windows wildcards, so there may be
even more cases of unexpected behavior.
If anyone knows where to find the complete rules (or a python module
that implements them), I would be interested.



fnmatch in the standard library has a translate function that transforms
a glob pattern to a regex

https://docs.python.org/3.7/library/fnmatch.html#fnmatch.translate

Alex


Thank you for the pointer.
However, from the documentation of module fnmatch:
"This module provides support for Unix shell-style wildcards"

And Unix shell-style wildcards differ from Windows cmd wildcards.
For one, [ ] are special in Unix shells, but not in Windows cmd.
For another, cmd wildcards have several quirks, e.g. *.* matching 
filenames that don't contain a dot, or "a???" matching "ab".


Several years ago, when I needed DOS-style globbing, I copied fnmatch.py 
and glob.py from the standard library and modified them to treat [ ] as 
not special. However, that didn't help with the cmd quirks, and I don't 
even know all the rules about cmd wildcards.


Ralf
--
https://mail.python.org/mailman/listinfo/python-list


Re: Spread a statement over various lines

2019-09-19 Thread Ralf M.

Am 18.09.2019 um 22:22 schrieb Chris Angelico:

On Thu, Sep 19, 2019 at 6:20 AM Ralf M.  wrote:


Am 17.09.2019 um 20:59 schrieb Manfred Lotz:

I have a function like follows

def regex_from_filepat(fpat):
  rfpat = fpat.replace('.', '\\.') \
.replace('%', '.')  \
.replace('*', '.*')

  return '^' + rfpat + '$'


As I don't want to have the replace() functions in one line my
question is if it is ok to spread the statement over various lines as
shown above, or if there is a better way?

Thanks.



Not related to your question, but:
You seem to try to convert a Windows wildcard pattern to a regex
pattern. However, wildcards sometimes behave a bit different than what
you assume. I know for instance that *.* matches any filename, even if
the filename doesn't contain a dot.


Hmm, why do you assume it's a Windows wildcard pattern specifically?

ChrisA

I think I jumped to that conclusion because the example didn't treat [ ] 
as special characters. [ ] are special in a unix shell, but not at a cmd 
prompt. Thinking it over, [ ] would need a much differnt treatment and 
might be left out of the example for that reason, though.


Also I may be biased: I mostly use Windows, Linux only occasionally.

Ralf M.

--
https://mail.python.org/mailman/listinfo/python-list


Re: Spread a statement over various lines

2019-09-18 Thread Ralf M.

Am 17.09.2019 um 20:59 schrieb Manfred Lotz:

I have a function like follows

def regex_from_filepat(fpat):
 rfpat = fpat.replace('.', '\\.') \
   .replace('%', '.')  \
   .replace('*', '.*')

 return '^' + rfpat + '$'


As I don't want to have the replace() functions in one line my
question is if it is ok to spread the statement over various lines as
shown above, or if there is a better way?

Thanks.



Not related to your question, but:
You seem to try to convert a Windows wildcard pattern to a regex 
pattern. However, wildcards sometimes behave a bit different than what 
you assume. I know for instance that *.* matches any filename, even if 
the filename doesn't contain a dot.


Out of curiosity I played around a bit, details below.
As you can see, there are other wildcard strangenesses, e.g.
- ? does not match a dot
-  between letters etc. matches exactly 4 characters, but
   at the end or directly before a dot matches at most 4 characters

I don't know the exact rules of Windows wildcards, so there may be even 
more cases of unexpected behavior.
If anyone knows where to find the complete rules (or a python module 
that implements them), I would be interested.


Regards,
Ralf

- Details (Win 7 home SP1) -

C:\tmp>more pydirb.py
#!/usr/bin/env python3

import os, re, sys

def regex_from_filepat(fpat):
rfpat = fpat.replace('.', '\\.') \
.replace('?', '.')   \
.replace('*', '.*')
return '^' + rfpat + '$'

regexfilepat = re.compile(regex_from_filepat(sys.argv[1]))

for name in os.listdir():
if regexfilepat.match(name):
print(name)

C:\tmp>dir /b *
foo
foo.bar
foo.bar.c
foo.c
pydirb.py

C:\tmp>pydirb *
foo
foo.bar
foo.bar.c
foo.c
pydirb.py

C:\tmp>dir /b *.*
foo
foo.bar
foo.bar.c
foo.c
pydirb.py

C:\tmp>pydirb *.*
foo.bar
foo.bar.c
foo.c
pydirb.py

C:\tmp>dir /b *.*.*.*.*
foo
foo.bar
foo.bar.c
foo.c
pydirb.py

C:\tmp>pydirb *.*.*.*.*

C:\tmp>dir /b foo.?
foo
foo.c

C:\tmp>pydirb foo.?
foo.c

C:\tmp>dir /b foo.
foo
foo.bar
foo.c

C:\tmp>pydirb foo.

C:\tmp>dir /b foo?bar
Datei nicht gefunden

C:\tmp>pydirb foo?bar
foo.bar

C:\tmp>dir /b f?o.bar
foo.bar

C:\tmp>pydirb f?o.bar
foo.bar

C:\tmp>dir /b f??o.bar
Datei nicht gefunden

C:\tmp>pydirb f??o.bar

C:\tmp>dir /b fo?.bar
foo.bar

C:\tmp>pydirb fo?.bar
foo.bar

C:\tmp>dir /b fo??.bar
foo.bar

C:\tmp>pydirb fo??.bar

C:\tmp>dir /b foo??.bar
foo.bar

C:\tmp>pydirb foo??.bar
--
https://mail.python.org/mailman/listinfo/python-list


Multidimensional dicts

2019-09-06 Thread Ralf M.
Recently I wrote a quick and dirty script to do some counting and 
statistics. When I re-read it a bit later I noticed that I had been 
using two different ways to create two-dimensional (default-)dicts. Now 
I'm wondering whether one of them is "better" or more pythonic than the 
other.


What I did:

ddd_a = collections.defaultdict(set)
ddd_a[(key1, key2)].add(foo)

ddd_b = collections.defaultdict(lambda: collections.defaultdict(set))
ddd_b[key1][key2].add(foo)

Both work as expected.

Trying to think about differences I only noticed that ddd_a more easily 
generalises to more dimensions, and ddd_b has the benefit that 
ddd_b[key1] is a dict, which might help if one "row" needs to be fed to 
a function that expects a dict.


More general ddd_a looks more symmetric (key1 and key2 are exchangeable, 
if done consistently) and ddd_b looks more hierarchic (like a tree 
traversed from root to leaves where key1, key2 etc. determine which way 
to go at each level). ddd_b also is more simmilar to how two-dimensional 
lists are done in python.


Any recommendations / comments as to which to prefer?
--
https://mail.python.org/mailman/listinfo/python-list