Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 04/24/2016 08:20 AM, Ian Kelly wrote: On Sun, Apr 24, 2016 at 1:20 AM, Ethan Furman wrote: What fun things can Java enums do? Everything that Python enums can do, plus: > --> Planet.EARTH.value (5.976e+24, 6378140.0) --> Planet.EARTH.surface_gravity 9.802652743337129 This is incredibly useful, but it has a flaw: the value of each member of the enum is just the tuple of its arguments. Suppose we added a value for COUNTER_EARTH describing a hypothetical planet with the same mass and radius existing on the other side of the sun. [1] Then: --> Planet.EARTH is Planet.COUNTER_EARTH True If using Python 3 and aenum 1.4.1+, you can do --> class Planet(Enum, settings=NoAlias, init='mass radius'): ... MERCURY = (3.303e+23, 2.4397e6) ... VENUS = (4.869e+24, 6.0518e6) ... EARTH = (5.976e+24, 6.37814e6) ... COUNTER_EARTH = EARTH ... @property ... def surface_gravity(self): ... # universal gravitational constant (m3 kg-1 s-2) ... G = 6.67300E-11 ... return G * self.mass / (self.radius * self.radius) ... --> Planet.EARTH.value (5.976e+24, 6378140.0) --> Planet.EARTH.surface_gravity 9.802652743337129 --> Planet.COUNTER_EARTH.value (5.976e+24, 6378140.0) --> Planet.COUNTER_EARTH.surface_gravity 9.802652743337129 Planet.EARTH is Planet.COUNTER_EARTH False * Speaking of AutoNumber, since Java enums don't have the instance/value distinction, they effectively do this implicitly, only without generating a bunch of ints that are entirely irrelevant to your enum type. With Python enums you have to follow a somewhat arcane recipe to avoid specifying values, which just generates some values and then hides them away. And it also breaks the Enum alias feature: --> class Color(AutoNumber): ... red = default = () # not an alias! ... blue = () ... Another thing you could do here: --> class Color(Enum, settings=AutoNumber): ... red ... default = red ... blue ... --> list(Color) [, ] --> Color.default is Color.red True -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, Apr 24, 2016 at 2:08 PM Steven D'Apranowrote: > On Sun, 24 Apr 2016 04:40 pm, Michael Selik wrote: > > I think we're giving mixed messages because we're conflating > "constants" and globals that are expected to change. > > When you talk about "state", that usually means "the current state of the > program", not constants. math.pi is not "state". > Perhaps I was unclear. You provided an example of what I was trying to point out. -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Sun, Apr 24, 2016 at 10:04 AM, Ethan Furmanwrote: > On 04/24/2016 08:20 AM, Ian Kelly wrote: >> * Java doesn't have the hokey notion of enum instances being distinct >> from their "value". The individual enum members *are* the values. >> Whereas in Python an enum member is an awkward class instance that >> contains a value of some other type. Python tries to get away from the >> C-like notion that enums are ints by making the enum members >> non-comparable, but then gives us IntEnum as a way to work around it >> if we really want to. Since Java enums don't depend on any other type >> for their values, there's nothing inviting the user to treat enums as >> ints in the first place. > > > How does Java share enums with other programs, computers, and/or languages? Java enums are serializable using the name. If you need it to be interoperable with other languages where they're int-based, then you could attach that value as a field. But that would just be data; you wouldn't be making that value an integral part of the Java enum just because some other language does it that way. >> Because they have the same "value", instead of creating a separate >> member, COUNTER_EARTH gets defined as an alias for EARTH. To work >> around this, one would have to add a third argument to the above to >> pass in an additional value for the sole purpose of distinguishing (or >> else adapt the AutoNumber recipe to work with this example). This >> example is a bit contrived since it's generally not likely to come up >> with floats, but it can easily arise (and in my experience frequently >> does) when the arguments are of more discrete types. It's notable that >> the Java enum docs feature this very same example but without this >> weakness. [2] > > > One reason for this is that Python enums are lookup-able via the value: > Planet(9.80265274333129) > Planet.EARTH > > Do Java enums not have such a feature, or this "feature" totally unnecessary > in Java? It's unnecessary. If you want to look up an enum constant by something other than name, you'd provide a static method or mapping. I'd argue that it's unnecessary in Python too for the same reason. But as long as Python enums make a special distinction of their value, there might as well be a built-in way to do it. > I could certainly add a "no-alias" feature to aenum. What would be the > appropriate value-lookup behaviour in such cases? > > - return the first match > - return a list of matches > - raise an error > - disable value-lookups for that Enum Probably the third or fourth, as I think that value lookup would generally not be useful in such cases, and it can be overridden if desired. > Cool. The stdlib Enum (and therefore the enum34 backport) is unlikely to > change much. However, aenum has a few fun things going on, and I'm happy to > add more: > > - NamedTuple (metaclass-based) > - NamedConstant (no aliases, no by-value lookups) > - Enum > - magic auto-numbering > class Number(Enum, auto=True): > one, two, three > def by_seven(self): > return self.value * 7 > - auto-setting of attributes >class Planet(Enum, init='mass radius'): > MERCURY = 3.303e23, 2.4397e6 > EARTH = 5.976e24, 6.37814e6 > NEPTUNE = 1.024e26, 2.4746e7 >--> Planet.EARTH.mass >5.976e24 Neat! -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 04/24/2016 11:27 AM, Chris Angelico wrote: On Mon, Apr 25, 2016 at 4:12 AM, Ethan Furman wrote: Values can be anything. The names are immutable and hashable. I know they *can* be, because I looked in the docs; but does it make sense to a human? Sure, we can legally do this: Well, not me. ;) --> class Color(Enum): ... red = 1 ... green = 2 ... blue = 3 ... break_me = [0xA0, 0xF0, 0xC0] ... --> Color([0xA0, 0xF0, 0xC0]) --> Color([0xA0, 0xF0, 0xC0]).value.append(1) --> Color([0xA0, 0xF0, 0xC0]).value.append(1) If you are looking up by value, you have to use the current value. Looks like pebkac error to me. ;) At some point, we're moving beyond the concept of "enumeration" and settling on "types.SimpleNamespace". Sure. But like most things in Python I'm not going to enforce it. And if somebody somewhere has a really cool use-case for it, more power to 'em. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Mon, Apr 25, 2016 at 4:12 AM, Ethan Furmanwrote: > On 04/24/2016 09:47 AM, Chris Angelico wrote: > >> I would normally expect enumerated values to be immutable and >> hashable, but that isn't actually required by the code AIUI. Under >> what circumstances is it useful to have mutable enum values? > > > Values can be anything. The names are immutable and hashable. I know they *can* be, because I looked in the docs; but does it make sense to a human? Sure, we can legally do this: >>> class Color(Enum): ... red = 1 ... green = 2 ... blue = 3 ... break_me = [0xA0, 0xF0, 0xC0] ... >>> Color([0xA0, 0xF0, 0xC0]) >>> Color([0xA0, 0xF0, 0xC0]).value.append(1) >>> Color([0xA0, 0xF0, 0xC0]).value.append(1) Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.6/enum.py", line 241, in __call__ return cls.__new__(cls, value) File "/usr/local/lib/python3.6/enum.py", line 476, in __new__ raise ValueError("%r is not a valid %s" % (value, cls.__name__)) ValueError: [160, 240, 192] is not a valid Color but I don't think it's a good thing to ever intentionally do. It's fine for the Enum class to not enforce it (it means you can use arbitrary objects as values, and that's fine), but if you actually do this, then . At some point, we're moving beyond the concept of "enumeration" and settling on "types.SimpleNamespace". ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 04/24/2016 09:47 AM, Chris Angelico wrote: I would normally expect enumerated values to be immutable and hashable, but that isn't actually required by the code AIUI. Under what circumstances is it useful to have mutable enum values? Values can be anything. The names are immutable and hashable. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, 24 Apr 2016 04:40 pm, Michael Selik wrote: > I think we're giving mixed messages because we're conflating "constants" > and globals that are expected to change. When you talk about "state", that usually means "the current state of the program", not constants. math.pi is not "state". > In our case here, I think two clients in the same process sharing state > might be a feature rather than a bug. Or at least it has the same behavior > as the current implementation. I don't think so. Two clients sharing state is exactly what makes thread programming with shared state so exciting. Suppose you import the decimal module, and set the global context: py> import decimal py> decimal.setcontext(decimal.ExtendedContext) py> decimal.getcontext().prec = 18 py> decimal.Decimal(1)/3 Decimal('0.33') Great. Now a millisecond later you do the same calculation: py> decimal.Decimal(1)/3 Decimal('0.3') WTF just happened here??? The answer is, another client of the module, one you may not even know about, has set the global context: decimal.getcontext().prec = 5 and screwed you over but good. -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Mon, Apr 25, 2016 at 3:54 AM, BartCwrote: > On 24/04/2016 17:47, Chris Angelico wrote: >> >> On Mon, Apr 25, 2016 at 2:42 AM, Ethan Furman wrote: Easy: allow an empty list to have the same meaning as an empty tuple. Every time you have [] in your source code, you're guaranteed to get a new (unique) empty list, and then multiple assignment will work. >>> >>> >>> >>> *sigh* >>> >>> Where were you three years ago? ;) >>> >>> Actually, thinking about it a bit more, if we did that then one could not >>> use an empty list as an enum value. Why would one want to? No idea, but >>> to >>> make it nearly impossible I'd want a much better reason than a minor >>> inconvenience: >> >> >> I would normally expect enumerated values to be immutable and >> hashable, > > > And, perhaps, to be actual enumerations. (So that in the set (a,b,c,d), you > don't know nor care about the underlying values, except that they are > distinct.) Not necessarily; often, the Python enumeration has to sync up with someone else's, possibly in C. It might not matter that BUTTON_OK is 1 and BUTTON_CANCEL is 2, but you have to make sure that everyone agrees on those meanings. So when you build the Python module, it's mandatory that those values be exactly what they are documented as. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 24/04/2016 17:47, Chris Angelico wrote: On Mon, Apr 25, 2016 at 2:42 AM, Ethan Furmanwrote: Easy: allow an empty list to have the same meaning as an empty tuple. Every time you have [] in your source code, you're guaranteed to get a new (unique) empty list, and then multiple assignment will work. *sigh* Where were you three years ago? ;) Actually, thinking about it a bit more, if we did that then one could not use an empty list as an enum value. Why would one want to? No idea, but to make it nearly impossible I'd want a much better reason than a minor inconvenience: I would normally expect enumerated values to be immutable and hashable, And, perhaps, to be actual enumerations. (So that in the set (a,b,c,d), you don't know nor care about the underlying values, except that they are distinct.) -- Bartc -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Mon, Apr 25, 2016 at 2:42 AM, Ethan Furmanwrote: >> Easy: allow an empty list to have the same meaning as an empty tuple. >> Every time you have [] in your source code, you're guaranteed to get a >> new (unique) empty list, and then multiple assignment will work. > > > *sigh* > > Where were you three years ago? ;) > > Actually, thinking about it a bit more, if we did that then one could not > use an empty list as an enum value. Why would one want to? No idea, but to > make it nearly impossible I'd want a much better reason than a minor > inconvenience: I would normally expect enumerated values to be immutable and hashable, but that isn't actually required by the code AIUI. Under what circumstances is it useful to have mutable enum values? ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 04/24/2016 09:10 AM, Chris Angelico wrote: On Mon, Apr 25, 2016 at 2:04 AM, Ethan Furmanwrote: Unfortunately, the empty tuple tends to be a singleton, so there is no way to tell that red and default are (supposed to be) the same and blue is (supposed to be) different: --> a = b = () --> c = () --> a is b True --> a is c True If you have an idea on how to make that work I am interested. Easy: allow an empty list to have the same meaning as an empty tuple. Every time you have [] in your source code, you're guaranteed to get a new (unique) empty list, and then multiple assignment will work. *sigh* Where were you three years ago? ;) Actually, thinking about it a bit more, if we did that then one could not use an empty list as an enum value. Why would one want to? No idea, but to make it nearly impossible I'd want a much better reason than a minor inconvenience: class Numbers: def __init__(self, value=0): self.value = value def __call__(self, value=None): if value is None: value = self.value self.value = value + 1 return value a = Numbers() class SomeNumbers(Enum): one = a() two = a() five = a(5) six = seis = a() One extra character, and done. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Mon, Apr 25, 2016 at 2:04 AM, Ethan Furmanwrote: > Unfortunately, the empty tuple tends to be a singleton, so there is no way > to tell that red and default are (supposed to be) the same and blue is > (supposed to be) different: > > --> a = b = () > --> c = () > --> a is b > True > --> a is c > True > > If you have an idea on how to make that work I am interested. Easy: allow an empty list to have the same meaning as an empty tuple. Every time you have [] in your source code, you're guaranteed to get a new (unique) empty list, and then multiple assignment will work. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On 04/24/2016 08:20 AM, Ian Kelly wrote: On Sun, Apr 24, 2016 at 1:20 AM, Ethan Furman wrote: On 04/23/2016 06:29 PM, Ian Kelly wrote: Python enums are great. Sadly, they're still not quite as awesome as Java enums. What fun things can Java enums do? Everything that Python enums can do, plus: * You can override methods of individual values, not just the class as a whole. Good for implementing the strategy pattern, or for defining a default method implementation that one or two values do differently. In Python you can emulate the same thing by adding the method directly to the instance dict of the enum value, so this isn't really all that much of a difference. All non-dunder methods, at least. * Java doesn't have the hokey notion of enum instances being distinct from their "value". The individual enum members *are* the values. Whereas in Python an enum member is an awkward class instance that contains a value of some other type. Python tries to get away from the C-like notion that enums are ints by making the enum members non-comparable, but then gives us IntEnum as a way to work around it if we really want to. Since Java enums don't depend on any other type for their values, there's nothing inviting the user to treat enums as ints in the first place. How does Java share enums with other programs, computers, and/or languages? As far as value-separate-from-instance: if you want/need them to be the same thing, mix-in the type: class Planet(float, Enum): ... [see below for "no-alias" ideas/questions] NB: The enum and the value are still different ('is' fails) but equal. * As a consequence of the above, Java doesn't conflate enum values with their parameters. The Python enum docs give us this interesting example of an enum that takes arguments from its declaration: class Planet(Enum): ... MERCURY = (3.303e+23, 2.4397e6) ... VENUS = (4.869e+24, 6.0518e6) ... EARTH = (5.976e+24, 6.37814e6) ... MARS= (6.421e+23, 3.3972e6) ... JUPITER = (1.9e+27, 7.1492e7) ... SATURN = (5.688e+26, 6.0268e7) ... URANUS = (8.686e+25, 2.5559e7) ... NEPTUNE = (1.024e+26, 2.4746e7) ... def __init__(self, mass, radius): ... self.mass = mass # in kilograms ... self.radius = radius # in meters ... @property ... def surface_gravity(self): ... # universal gravitational constant (m3 kg-1 s-2) ... G = 6.67300E-11 ... return G * self.mass / (self.radius * self.radius) ... Planet.EARTH.value (5.976e+24, 6378140.0) Planet.EARTH.surface_gravity 9.802652743337129 This is incredibly useful, but it has a flaw: the value of each member of the enum is just the tuple of its arguments. Suppose we added a value for COUNTER_EARTH describing a hypothetical planet with the same mass and radius existing on the other side of the sun. [1] Then: Planet.EARTH is Planet.COUNTER_EARTH True Because they have the same "value", instead of creating a separate member, COUNTER_EARTH gets defined as an alias for EARTH. To work around this, one would have to add a third argument to the above to pass in an additional value for the sole purpose of distinguishing (or else adapt the AutoNumber recipe to work with this example). This example is a bit contrived since it's generally not likely to come up with floats, but it can easily arise (and in my experience frequently does) when the arguments are of more discrete types. It's notable that the Java enum docs feature this very same example but without this weakness. [2] One reason for this is that Python enums are lookup-able via the value: >>> Planet(9.80265274333129) Planet.EARTH Do Java enums not have such a feature, or this "feature" totally unnecessary in Java? I could certainly add a "no-alias" feature to aenum. What would be the appropriate value-lookup behaviour in such cases? - return the first match - return a list of matches - raise an error - disable value-lookups for that Enum * Speaking of AutoNumber, since Java enums don't have the instance/value distinction, they effectively do this implicitly, only without generating a bunch of ints that are entirely irrelevant to your enum type. With Python enums you have to follow a somewhat arcane recipe to avoid specifying values, which just generates some values and then hides them away. And it also breaks the Enum alias feature: class Color(AutoNumber): ... red = default = () # not an alias! ... blue = () ... Color.red is Color.default False Unfortunately, the empty tuple tends to be a singleton, so there is no way to tell that red and default are (supposed to be) the same and blue is (supposed to be) different: --> a = b = () --> c = () --> a is b True --> a is c True If you have an idea on how to make that work I am interested. Anyroad, I think that covers all my beefs with the way enums are implemented in Python. Despite the above, they're a great feature, and I use them and appreciate
Comparing Python enums to Java, was: How much sanity checking is required for function inputs?
On Sun, Apr 24, 2016 at 1:20 AM, Ethan Furmanwrote: > On 04/23/2016 06:29 PM, Ian Kelly wrote: > >> Python enums are great. Sadly, they're still not quite as awesome as Java >> enums. > > > What fun things can Java enums do? Everything that Python enums can do, plus: * You can override methods of individual values, not just the class as a whole. Good for implementing the strategy pattern, or for defining a default method implementation that one or two values do differently. In Python you can emulate the same thing by adding the method directly to the instance dict of the enum value, so this isn't really all that much of a difference. * Java doesn't have the hokey notion of enum instances being distinct from their "value". The individual enum members *are* the values. Whereas in Python an enum member is an awkward class instance that contains a value of some other type. Python tries to get away from the C-like notion that enums are ints by making the enum members non-comparable, but then gives us IntEnum as a way to work around it if we really want to. Since Java enums don't depend on any other type for their values, there's nothing inviting the user to treat enums as ints in the first place. * As a consequence of the above, Java doesn't conflate enum values with their parameters. The Python enum docs give us this interesting example of an enum that takes arguments from its declaration: >>> class Planet(Enum): ... MERCURY = (3.303e+23, 2.4397e6) ... VENUS = (4.869e+24, 6.0518e6) ... EARTH = (5.976e+24, 6.37814e6) ... MARS= (6.421e+23, 3.3972e6) ... JUPITER = (1.9e+27, 7.1492e7) ... SATURN = (5.688e+26, 6.0268e7) ... URANUS = (8.686e+25, 2.5559e7) ... NEPTUNE = (1.024e+26, 2.4746e7) ... def __init__(self, mass, radius): ... self.mass = mass # in kilograms ... self.radius = radius # in meters ... @property ... def surface_gravity(self): ... # universal gravitational constant (m3 kg-1 s-2) ... G = 6.67300E-11 ... return G * self.mass / (self.radius * self.radius) ... >>> Planet.EARTH.value (5.976e+24, 6378140.0) >>> Planet.EARTH.surface_gravity 9.802652743337129 This is incredibly useful, but it has a flaw: the value of each member of the enum is just the tuple of its arguments. Suppose we added a value for COUNTER_EARTH describing a hypothetical planet with the same mass and radius existing on the other side of the sun. [1] Then: >>> Planet.EARTH is Planet.COUNTER_EARTH True Because they have the same "value", instead of creating a separate member, COUNTER_EARTH gets defined as an alias for EARTH. To work around this, one would have to add a third argument to the above to pass in an additional value for the sole purpose of distinguishing (or else adapt the AutoNumber recipe to work with this example). This example is a bit contrived since it's generally not likely to come up with floats, but it can easily arise (and in my experience frequently does) when the arguments are of more discrete types. It's notable that the Java enum docs feature this very same example but without this weakness. [2] * Speaking of AutoNumber, since Java enums don't have the instance/value distinction, they effectively do this implicitly, only without generating a bunch of ints that are entirely irrelevant to your enum type. With Python enums you have to follow a somewhat arcane recipe to avoid specifying values, which just generates some values and then hides them away. And it also breaks the Enum alias feature: >>> class Color(AutoNumber): ... red = default = () # not an alias! ... blue = () ... >>> Color.red is Color.default False Anyroad, I think that covers all my beefs with the way enums are implemented in Python. Despite the above, they're a great feature, and I use them and appreciate that we have them. [1] https://en.wikipedia.org/wiki/Counter-Earth [2] https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 06:00 PM, Christopher Reimer wrote: Hmm... What do we use Enum for? :) from enum import Enum class Piece(Enum): king = 'one space, any direction' queen = 'many spaces, any direction' bishop = 'many spaces, diagonal' knight = 'two spaces cardinal, one space sideways, cannot be blocked' rook = 'many spaces, cardinal' pawn = 'first move: one or two spaces forward; subsequent moves: one space forward; attack: one space diagonal' --> list(Piece) [ , , , blocked'>, , moves: one space forward; attack: one space diagonal'>, ] --> p = Piece.bishop --> p in Piece True --> p is Piece.rook False --> p is Piece.bishop True -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 06:21 PM, Michael Selik wrote: On Sat, Apr 23, 2016 at 9:01 PM Christopher Reimer wrote: Hmm... What do we use Enum for? :) You can use Enum in certain circumstances to replace int or str constants. It can help avoid mistyping mistakes and might help your IDE give auto-complete suggestions. I haven't found a good use for them myself, but I'd been mostly stuck in Python 2 until recently. enum34 is the backport, aenum is the turbo charged version. https://pypi.python.org/pypi/enum34 https://pypi.python.org/pypi/aenum -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 06:29 PM, Ian Kelly wrote: Python enums are great. Sadly, they're still not quite as awesome as Java enums. What fun things can Java enums do? -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, Apr 24, 2016, 1:51 AM Steven D'Apranowrote: > On Sun, 24 Apr 2016 12:34 pm, Michael Torrie wrote: > > > There are many aspects to Pythonic programming, not just OOP. For > > example using modules to store shared state for your program components > > is very pythonic, rather than using classes. A module is kind of like a > > singleton instance, and still is object-oriented by the way (the module > > is an object). > > I find myself going backwards and forwards on whether or not that is a good > idea. I think it depends on whether you are writing a library or an > application. > > If you're writing an application, then storing state in module-level > variables works fine. Your application is, effectively, a singleton, and if > you try to run it twice, you'll (probably) be running it in two distinct > processes, so that's okay. > > (If you're not, if somehow you perform some sort of trickery where you have > a single Python interpreter running your script twice in the same process, > then it will break horribly. But if you can do that, you're living on the > edge already and can probably deal with it.) > > But if you're writing a library, then using module state is a Bad Idea. > Your > library may be used by more than one client in the same process, and they > will conflict over each other's library-level state. "Global variables > considered harmful." > I think we're giving mixed messages because we're conflating "constants" and globals that are expected to change. In our case here, I think two clients in the same process sharing state might be a feature rather than a bug. Or at least it has the same behavior as the current implementation. > -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
Steven D'Aprano: > On Sun, 24 Apr 2016 12:03 pm, Christopher Reimer wrote: > >> On 4/23/2016 2:33 PM, Matt Wheeler wrote: >>> This is still backwards to me. It prevents your classes from being >>> suitable for restoring a stored game state, not just custom starting >>> positions (which I think is what Ethan means by custom setups). >> >> I haven't thought that far about saving the game state. I'm under the >> impression that pickle (or something else) would save and load the >> instantiated object of each piece. If that's not the case, I'll change >> the code then. > > Pickle will do what you are thinking of, but pickle is not secure and > involves executing arbitrary code. If you cannot trust the source of > the pickle, then you should not use it. You shouldn't use your runtime objects as a storage format. Instead, design the storage objects separately and translate between runtime and storage objects as needed. JSON objects or straight Python dicts are good candidates for overall storage format. JSON would allow for easy interchange between different programming languages if need be. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, 24 Apr 2016 12:34 pm, Michael Torrie wrote: > There are many aspects to Pythonic programming, not just OOP. For > example using modules to store shared state for your program components > is very pythonic, rather than using classes. A module is kind of like a > singleton instance, and still is object-oriented by the way (the module > is an object). I find myself going backwards and forwards on whether or not that is a good idea. I think it depends on whether you are writing a library or an application. If you're writing an application, then storing state in module-level variables works fine. Your application is, effectively, a singleton, and if you try to run it twice, you'll (probably) be running it in two distinct processes, so that's okay. (If you're not, if somehow you perform some sort of trickery where you have a single Python interpreter running your script twice in the same process, then it will break horribly. But if you can do that, you're living on the edge already and can probably deal with it.) But if you're writing a library, then using module state is a Bad Idea. Your library may be used by more than one client in the same process, and they will conflict over each other's library-level state. "Global variables considered harmful." -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, 24 Apr 2016 12:03 pm, Christopher Reimer wrote: > On 4/23/2016 2:33 PM, Matt Wheeler wrote: >> This is still backwards to me. It prevents your classes from being >> suitable for restoring a stored game state, not just custom starting >> positions (which I think is what Ethan means by custom setups). > > I haven't thought that far about saving the game state. I'm under the > impression that pickle (or something else) would save and load the > instantiated object of each piece. If that's not the case, I'll change > the code then. Pickle will do what you are thinking of, but pickle is not secure and involves executing arbitrary code. If you cannot trust the source of the pickle, then you should not use it. -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 09:41 PM, Christopher Reimer wrote: > I never wanted to learn Java in the first place. My community college > couldn't afford to renew the Microsoft site license, which local > employers required to learn C/C++ in MS Visual Studio, and all flavors > of Java got taught for the programming classes instead. I wanted to > learn C/C++. I even wanted to learn assembly language, but I was the > only student who showed up for the class and it got cancelled. > > Of course, it probably doesn't help that I got a job in help desk > support after I graduated with A.S. degree in Java and never programmed > professionally. Thinking like a programmer helped me resolved many IT > problems over the last 12 years. My current job in computer security > requires tinkering with PowerShell scripts as Python is strictly > prohibited in this Windows shop. I have made Python my main programming > language at home. I don't mean to imply that I'm criticizing you for your Java experience! I am critical of Java, though. I'm very glad you've discovered Python and I hope you'll continue to have fun with it. I hope you'll take the advice offered by the others on this thread in stride and hopefully we'll all learn and benefit. I completely agree with you that learning to think like a programmer is so helpful in solving all kinds of problems, especially in IT! -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/23/2016 8:19 PM, Michael Torrie wrote: The reason you weren't taught beyond class inheritance is because Java implements organization only through a class hierarchy. Whole generations of Java programmers think that program organization is through classes (a static main method means your code is procedural, by the way). I never wanted to learn Java in the first place. My community college couldn't afford to renew the Microsoft site license, which local employers required to learn C/C++ in MS Visual Studio, and all flavors of Java got taught for the programming classes instead. I wanted to learn C/C++. I even wanted to learn assembly language, but I was the only student who showed up for the class and it got cancelled. Of course, it probably doesn't help that I got a job in help desk support after I graduated with A.S. degree in Java and never programmed professionally. Thinking like a programmer helped me resolved many IT problems over the last 12 years. My current job in computer security requires tinkering with PowerShell scripts as Python is strictly prohibited in this Windows shop. I have made Python my main programming language at home. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 08:32 PM, Christopher Reimer wrote: > That's the other problem I'm running into. Building a chess engine is a > big project. This is probably bigger than the Java XML parser I built > from scratch for a college project. I can't seem to find any information > on how to build bigger programs. Community college taught me how to > program, but it didn't teach me how to go beyond class inheritance. The reason you weren't taught beyond class inheritance is because Java implements organization only through a class hierarchy. Whole generations of Java programmers think that program organization is through classes (a static main method means your code is procedural, by the way). Learn about Python namespaces and how to use them. I guess it just comes with experience, a lot of trial and a lot of error. And checking on how others are doing it. Take a look at examples from the Python standard library, as well as other projects. For example, Beautiful Soup. Not that you have to understand their code, but take a look at how they organize things. In my mind namespaces matter more than files as an organizational tool. Because namespaces are my primary organization, I will put multiple class definitions in the same file (if they belong in the same namespace), so they can be imported from the same module. If the classes and functions get more complicated, I can separate them into their own submodules and wrap them all up in one Python package (like a module but more flexible and has submodules). The nice thing about building with Python is you can start with one thing, like a module, and convert it to a package later on as needed. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/23/2016 7:34 PM, Michael Torrie wrote Procedural programming does not necessarily mean BASIC-style goto hell. Not sure why you would think that. In fact that's not really what procedural programming is about. I mentioned several messages back that I spent two years writing procedural scripts AND translating BASIC games into Python, which can be goto hell if the program has a drop-down structure that makes sense only from following the entry point of the goto statement (see link for example). http://www.atariarchives.org/basicgames/showpage.php?page=9 I try to follow the BASIC program structure as closely as possible, get it working in Python, and use pylint to make my code PEP8-compliant. Pylint frequently complains about exceeding a dozen if branches in the main function. I then create helper functions to reduce the if branches. Sometimes that makes the Python version either shorter or longer than the original BASIC program. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/23/2016 07:45 PM, Christopher Reimer wrote: > I had to confront all the bad habits I brought over Java and change my > code to be more Pythonic. This is where I started having fun, learning > the tricks and collapsing multi-line code into a single line code. I've > learned more about Python in the few weeks than I had in two years of > writing procedural scripts and translating BASIC goto hell. Procedural programming does not necessarily mean BASIC-style goto hell. Not sure why you would think that. In fact that's not really what procedural programming is about. However, Mr. Selik wasn't advocating procedural programming at all. Not defining a class does not make your code precdural. But using classes does not mean your code is *not* procedural. If you are using an event-driven framework then I will say, yes your code is not procedural. There are many aspects to Pythonic programming, not just OOP. For example using modules to store shared state for your program components is very pythonic, rather than using classes. A module is kind of like a singleton instance, and still is object-oriented by the way (the module is an object). Sadly Java really messed up people by using classes as a namespace mechanism. That was quite a mistake. Really messed with people's expectations of OOP. I would say that pythonic programming involves defining classes when it's appropriate, and not doing so when something else will work just as well and be simpler. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/23/2016 6:38 PM, Michael Selik wrote: Why so many files? Python can easily support thousands of lines in a file. If it's just one file any text editor can do a quick find-replace. That goes back to the Java convention of having one class per file. It took a while to convince myself that mixing classes and functions in a single file was okay. Once I finished cleaning up the code for this round, I'll merge four files into one file (~500 lines) and have four files (main.py, display.py, engine.py and utility.py). Or just use one file to keep things easier. But, yes, I agree a module of constants is appropriate for bigger projects. That's the other problem I'm running into. Building a chess engine is a big project. This is probably bigger than the Java XML parser I built from scratch for a college project. I can't seem to find any information on how to build bigger programs. Community college taught me how to program, but it didn't teach me how to go beyond class inheritance. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/23/2016 6:29 PM, Ian Kelly wrote: Python enums are great. Sadly, they're still not quite as awesome as Java enums. I remember enums more from C than Java. Although I haven't used them much in either language. I'm planning to immerse myself back into C via Cython. Depending on far I get into this chess program, I might need a speed boost here and there. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/23/2016 2:33 PM, Matt Wheeler wrote: This is still backwards to me. It prevents your classes from being suitable for restoring a stored game state, not just custom starting positions (which I think is what Ethan means by custom setups). I haven't thought that far about saving the game state. I'm under the impression that pickle (or something else) would save and load the instantiated object of each piece. If that's not the case, I'll change the code then. The sanity check does have an exemption for pawn promotion, where a pawn reaching the other side of the board can be promoted to another piece (typically a queen). I played Sargon II chess on the Commodore 64 for five years as a teenager. The worst game I ever won was when the computer had nine queens on the board. I thought the computer was cheating outrageously but a chess rule book confirmed that promotion was a legit move. https://en.wikipedia.org/wiki/Promotion_(chess) If I need to add an exemption to custom plays, I'll add it then. Right now I'm cleaning up the existing code from all the bad Java habits. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/22/2016 1:40 PM, Michael Selik wrote: Frankly, for someone coming from Java, the best advice is to not write any classes until you must. Of course classes in Python are very useful. It's just that your Java habits are unnecessary and often counter-productive. I disagree. I wrote procedural scripts and translated old BASIC games into Python for two years. One day I came across a Python book that described the principles of subclassing from a base class for chess pieces, but there was no code to demonstrate the process. I had no problem creating the Python classes. That's how my research project got started to build a chess engine. If you ever check the academic literature for chess programming, this research project could turn into a lifelong endeavor. I had to confront all the bad habits I brought over Java and change my code to be more Pythonic. This is where I started having fun, learning the tricks and collapsing multi-line code into a single line code. I've learned more about Python in the few weeks than I had in two years of writing procedural scripts and translating BASIC goto hell. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sat, Apr 23, 2016 at 9:31 PM Christopher Reimer < christopher_rei...@icloud.com> wrote: > On 4/21/2016 10:25 PM, Stephen Hansen wrote: > > > > Why not, 'color in ("black", "white")'? > > Checkers seems popular around here. What if I want to change "white" to > "red," as red and black is a common color scheme for checkers. Do I > change a single constant variable or replace all the occurrences in the > files? > Why so many files? Python can easily support thousands of lines in a file. If it's just one file any text editor can do a quick find-replace. That said, it's easy to make some global ``red = 'red'``. Some of these constants are shortcuts. Instead of writing slice(0, 16) > or slice(48, 64), and getting the two confused, I write > const['board_bottom'] or const['board_top'], respectively, when I want > to pull the correct set of positions from coordinates list. > Why hide these things in a dict ``const`` instead of just making them top-level variables in the module themselves? ``board_top = slice(48, 64)`` > That said, if you're wanting to share constants across different parts > > of your code, use a module. > Or just use one file to keep things easier. But, yes, I agree a module of constants is appropriate for bigger projects. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sat, Apr 23, 2016 at 7:00 PM, Christopher Reimerwrote: > On 4/21/2016 9:46 PM, Ethan Furman wrote: >> >> Oh! and Enum!!! ;) > > > OMG! I totally forgot about Enum. Oh, look. Python supports Enum. Now I > don't have to roll my own! > > Hmm... What do we use Enum for? :) Python enums are great. Sadly, they're still not quite as awesome as Java enums. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/21/2016 10:25 PM, Stephen Hansen wrote: Why not, 'color in ("black", "white")'? Checkers seems popular around here. What if I want to change "white" to "red," as red and black is a common color scheme for checkers. Do I change a single constant variable or replace all the occurrences in the files? Some of these constants are shortcuts. Instead of writing slice(0, 16) or slice(48, 64), and getting the two confused, I write const['board_bottom'] or const['board_top'], respectively, when I want to pull the correct set of positions from coordinates list. That said, if you're wanting to share constants across different parts of your code, use a module. I did that at first, made it into a dictionary class and added ConfigParser to the mix. I had a lot of fun putting that one together. However, as I refactor my code further as I learn new things, it will probably get changed or removed. Being a research project, I'm willing to dive into every rabbit hole that I come across to learn Python properly. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sat, Apr 23, 2016 at 9:01 PM Christopher Reimer < christopher_rei...@icloud.com> wrote: > On 4/21/2016 9:46 PM, Ethan Furman wrote: > > Oh! and Enum!!! ;) > > OMG! I totally forgot about Enum. Oh, look. Python supports Enum. Now I > don't have to roll my own! > > Hmm... What do we use Enum for? :) > You can use Enum in certain circumstances to replace int or str constants. It can help avoid mistyping mistakes and might help your IDE give auto-complete suggestions. I haven't found a good use for them myself, but I'd been mostly stuck in Python 2 until recently. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/21/2016 9:46 PM, Ethan Furman wrote: Oh! and Enum!!! ;) OMG! I totally forgot about Enum. Oh, look. Python supports Enum. Now I don't have to roll my own! Hmm... What do we use Enum for? :) Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 22 April 2016 at 04:11, Christopher Reimerwrote: > On 4/21/2016 7:10 PM, Ethan Furman wrote: >>> I do plan to incorporate a sanity test in each Piece class to validate >>> the initial position value. Pawns have 16 specific positions. Bishop, >>> Knight and Rook each have four specific positions. King and Queen each >>> have two specific positions. An invalid value will raise an exception. >> >> This will make it so you cannot use your PieceFactory for custom setups. > > The sanity check won't be in the PieceFactory, but in the Piece class as an > interface and each Piece subclass will implement the correct positions for > comparison. This is still backwards to me. It prevents your classes from being suitable for restoring a stored game state, not just custom starting positions (which I think is what Ethan means by custom setups). If you need to put sanity checking in your initialisation at all it should be at some higher level, probably in a method named something like `start_chess_game`. But really I'd suggest just writing tests for that method to make sure it's doing the right thing. On the other hand (and I'm sure you've already thought of this) it probably does make sense to put piece move validation in to each of the piece classes: you could even have some fun with it... def move_straight(old, new): if old[0] == new[0] or old[1] == new[1]: return True def move_diag(old, new): diff_x = abs(old[0] - new[0]) diff_y = abs(old[1] - new[1]) if diff_x == diff_y: return True class Piece: ... def move(self, new): if self.validate_move(new): # do the move ... else: raise IllegalMove('or something') class Queen(Piece): def validate_move(self, new): return any((test(self.position, new) for test in (move_straight, move_diag))) Ok I'll stop before I get too carried away... This is completely untested so bugs will abound I'm sure :) -- Matt Wheeler http://funkyh.at -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Fri, Apr 22, 2016, 1:26 AM Stephen Hansenwrote: > On Thu, Apr 21, 2016, at 08:33 PM, Christopher Reimer wrote: > > On 4/21/2016 7:20 PM, Stephen Hansen wrote: > > > I... that... what... I'd forget that link and pretend you never went > > > there. Its not helpful. > > > > I found it on the Internet, so it must be true -- and Pythonic at that! > > My advice is to not look at that site further. I can't count the number > of things that are just... not useful or helpful. > > Directly translating the Gang of Four Design Pattern book to Python > doesn't generally result in useful ideas, except in certain abstractions > like the visitor pattern when you're designing big systems. > Frankly, for someone coming from Java, the best advice is to not write any classes until you must. Of course classes in Python are very useful. It's just that your Java habits are unnecessary and often counter-productive. Just make some globals and some functions. Heck, even write procedurally for a while. Free yourself from the Kingdom of Nouns. http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html > -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Thu, Apr 21, 2016, at 08:33 PM, Christopher Reimer wrote: > On 4/21/2016 7:20 PM, Stephen Hansen wrote: > > I... that... what... I'd forget that link and pretend you never went > > there. Its not helpful. > > I found it on the Internet, so it must be true -- and Pythonic at that! My advice is to not look at that site further. I can't count the number of things that are just... not useful or helpful. Directly translating the Gang of Four Design Pattern book to Python doesn't generally result in useful ideas, except in certain abstractions like the visitor pattern when you're designing big systems. > > > What's the contents of this big dictionary that has everything in it > > for some reason? > > Keep in mind that I'm coming from a Java background (not by choice) with > a smattering of C programming. I initially had ALL THESE CONSTANTS in > different parts of my code and couldn't easily use them across different > modules. I didn't like all these constants, created a singleton class > that uses ConfigParser, dumped everything into a .ini file, and accessed > from in each module. As I learn to write Pythonic code, the constants > may go away. Switching from my original code to the factory method > eliminated a half-dozen constants. I'm not criticizing, I'm *asking* in the hopes you'll explain what you're doing better, so I can understand and give advice that's more relevant: I don't understand what it is you're doing with the VARS or const dictionary. Even with your explanation here, I don't get it. Why do you need to read VARS["COLOR_BLACK"] or the new const["COLOR_BLACK"} from a configuration file? How is this stuff configurable? Why not, 'color in ("black", "white")'? The only reason I can think of why you'd want to read what is "black" or "white" out of a configuration file is internationalization, and if that's your aim, there's a couple really good projects I can recommend that solve that issue better. I can't think of any reason why you'd want a structure like: struct = {} struct["COLOR_BLACK"] = "black" struct["COLOR_WHITE"] = "white" "black" is a perfectly good way to express "black", you have this indirection/abstraction for a reason I don't understand. Granted, maybe this is a heavy javaism, and I'm utterly ignorant of Java, but my C/C++ mind can't think of a reason for this either. That said, if you're wanting to share constants across different parts of your code, use a module. Create a module, say, things.py, that itself doesn't import other things, and it says: black = "Black" white = "White" (Bear in mind I still don't know why you want or need this indirection) Then you "import things" and refer to those constants as things.black, things.white. You can then "if color in (things.black, things.white)". Maybe even "if color in things.colors" if in your things file you have things = (black, white). Modules are great for sharing information. The admonition of GLOBALS R BAD is not as strong in Python as you find in some other languages. (Don't take that to mean GLOBALS R GUD, granted. Passing state is best when it makes sense). --S m e @ i x o k a i . i o -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/21/2016 08:33 PM, Christopher Reimer wrote: On 4/21/2016 7:20 PM, Stephen Hansen wrote: Keep in mind that I'm coming from a Java background (not by choice) with a smattering of C programming. A refugee! Water! Food! import this!! :) Oh! and Enum!!! ;) -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/21/2016 7:20 PM, Stephen Hansen wrote: Whyyy are you using getattr? Something wrong with PieceFactory.factory(color, piece, position)? (Or, better yet, yield piece_factory(color, piece, position) where piece_factory is just a function) Because the example I found used it, I implemented it, and it worked in my code. Based on feedback that I gotten from this list, I'll go back and clean it up. I... that... what... I'd forget that link and pretend you never went there. Its not helpful. I found it on the Internet, so it must be true -- and Pythonic at that! What's the contents of this big dictionary that has everything in it for some reason? Keep in mind that I'm coming from a Java background (not by choice) with a smattering of C programming. I initially had ALL THESE CONSTANTS in different parts of my code and couldn't easily use them across different modules. I didn't like all these constants, created a singleton class that uses ConfigParser, dumped everything into a .ini file, and accessed from in each module. As I learn to write Pythonic code, the constants may go away. Switching from my original code to the factory method eliminated a half-dozen constants. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/21/2016 7:10 PM, Ethan Furman wrote: I do plan to incorporate a sanity test in each Piece class to validate the initial position value. Pawns have 16 specific positions. Bishop, Knight and Rook each have four specific positions. King and Queen each have two specific positions. An invalid value will raise an exception. This will make it so you cannot use your PieceFactory for custom setups. The sanity check won't be in the PieceFactory, but in the Piece class as an interface and each Piece subclass will implement the correct positions for comparison. Thank you, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/21/2016 6:54 PM, Tim Chase wrote: I'd simplify this code to something like class PieceFactory(object): @staticmethod def factory(color, piece, position): try: return { 'Bishop': Bishop, 'King': King, 'Knight': Knight, 'Pawn': Pawn, 'Queen': Queen, 'Rook': Rook, }[piece](color, position) except KeyError: raise PieceException(...) I like this better. I'll probably remove the try/except and let the KeyError filter up. Thanks, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Fri, 22 Apr 2016 11:34 am, Christopher Reimer wrote: > Greetings, > > Thanks to everyone for providing feedback. Here's my revised code to > generate a set of chess pieces. > class PieceFactory(object): > > def factory(color, piece, position): > if piece == 'Bishop': > return Bishop(color, position) > if piece == 'King': > return King(color, position) > if piece == 'Knight': > return Knight(color, position) > if piece == 'Pawn': > return Pawn(color, position) > if piece == 'Queen': > return Queen(color, position) > if piece == 'Rook': > return Rook(color, position) > > raise PieceException('No valid Piece object for factory, > got {}' > ' instead'.format(piece)) > > factory = staticmethod(factory) Eww :-) Creating an entire class with no state just to hold one method is an abuse of classes. If your class doesn't include both state (data) and behaviour (methods), it probably shouldn't be a class. class King: ... class Queeen: ... # etc. PIECES = dict((piece.__name__, piece) for piece in [King, Queen, Bishop, Knight, Rook, Pawn]) def make_piece(color, name, position): name = name.title() # Accept 'king', 'KING', 'King' etc. P = PIECES.get(name, None) if P is None: raise PieceException('unknown name %r' % name) return P(color, position) > def generate_set(color, pieces, positions): > for piece, position in zip(pieces, positions): > yield getattr(PieceFactory, 'factory')(color, piece, position) def generate_pieces(color, names, positions): for name, position in zip(names, positions): yield make_piece(color, name, position) -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 2016-04-21 18:34, Christopher Reimer wrote: > class PieceFactory(object): > > def factory(color, piece, position): > if piece == 'Bishop': > return Bishop(color, position) > if piece == 'King': > return King(color, position) > if piece == 'Knight': > return Knight(color, position) > if piece == 'Pawn': > return Pawn(color, position) > if piece == 'Queen': > return Queen(color, position) > if piece == 'Rook': > return Rook(color, position) > > raise PieceException('No valid Piece object for > factory, got {}' > ' instead'.format(piece)) > > factory = staticmethod(factory) I'd simplify this code to something like class PieceFactory(object): @staticmethod def factory(color, piece, position): try: return { 'Bishop': Bishop, 'King': King, 'Knight': Knight, 'Pawn': Pawn, 'Queen': Queen, 'Rook': Rook, }[piece](color, position) except KeyError: raise PieceException(...) which removes some of the redundancy. I might even be tempted to simply ignore the exception and let the KeyError percolate up the call-stack if someone calls it with an unknown piece/key, rather than converting it into a PieceException. -tkc -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Thu, Apr 21, 2016, at 06:34 PM, Christopher Reimer wrote: > class PieceFactory(object): > > def factory(color, piece, position): > if piece == 'Bishop': > return Bishop(color, position) > if piece == 'King': > return King(color, position) > if piece == 'Knight': > return Knight(color, position) > if piece == 'Pawn': > return Pawn(color, position) > if piece == 'Queen': > return Queen(color, position) > if piece == 'Rook': > return Rook(color, position) This whole section is begging for a dictionary. Like... _PIECE_TYPES= {"Bishop": Bishop, "King": King, ...] class PieceFactory(object): def factory(color, piece, position): klass = __PIECE_TYPES.get(piece) if klass is None: raise PieceException("...") return klass(color, position) Or something like that. That said, I'm not sure why its not just a function that does the same thing. Why is it in a class that only does one thing? You never even instantiate it. > def generate_set(color, pieces, positions): > for piece, position in zip(pieces, positions): > yield getattr(PieceFactory, 'factory')(color, piece, position) Whyyy are you using getattr? Something wrong with PieceFactory.factory(color, piece, position)? (Or, better yet, yield piece_factory(color, piece, position) where piece_factory is just a function) > I got the factory method from here: > http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Factory.html I... that... what... I'd forget that link and pretend you never went there. Its not helpful. > Finally, VARS['VARIABLE_NAME'] got change to const['variable_name']. > Should smell better. I don't know that this changes anything about the small at all. What's the contents of this big dictionary that has everything in it for some reason? That said, dear god, 'piece' doesn't look like an english word to me anymore. I've never suffered semantic satiation from text before. --Stephen m e @ i x o k a i . i o -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/21/2016 06:34 PM, Christopher Reimer wrote: class PieceFactory(object): > [...] Better. I do plan to incorporate a sanity test in each Piece class to validate the initial position value. Pawns have 16 specific positions. Bishop, Knight and Rook each have four specific positions. King and Queen each have two specific positions. An invalid value will raise an exception. This will make it so you cannot use your PieceFactory for custom setups. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
Greetings, Thanks to everyone for providing feedback. Here's my revised code to generate a set of chess pieces. class PieceFactory(object): def factory(color, piece, position): if piece == 'Bishop': return Bishop(color, position) if piece == 'King': return King(color, position) if piece == 'Knight': return Knight(color, position) if piece == 'Pawn': return Pawn(color, position) if piece == 'Queen': return Queen(color, position) if piece == 'Rook': return Rook(color, position) raise PieceException('No valid Piece object for factory, got {}' ' instead'.format(piece)) factory = staticmethod(factory) def generate_set(color, pieces, positions): for piece, position in zip(pieces, positions): yield getattr(PieceFactory, 'factory')(color, piece, position) The input values for 'pieces' and 'positions' are 16-item lists zipped together to produce a piece name and a position coordinate for the factory method. With slight modifications to the code, the factory method could also return checker pieces. I got the factory method from here: http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Factory.html I do plan to incorporate a sanity test in each Piece class to validate the initial position value. Pawns have 16 specific positions. Bishop, Knight and Rook each have four specific positions. King and Queen each have two specific positions. An invalid value will raise an exception. Finally, VARS['VARIABLE_NAME'] got change to const['variable_name']. Should smell better. Thanks, Chris R -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Tue, Apr 19, 2016, at 11:09 PM, Ethan Furman wrote: > On 04/19/2016 10:51 PM, Stephen Hansen wrote: > > I use 1) more to be less 'nicer' and more, er, 'more specific'. Since I > > don't like exceptions to rise to the user level where niceness is > > needed. > > Yeah, that's a better phrasing for (1); I meant more appropriate or > informative, such as swapping an internal error (such as KeyError) for a > more meaningful FieldNotFound error (or whatever) -- largely library > code concerns. Yeah, and what the OP is doing is going the exact opposite-- from a more-specific exception (KeyError) to a more generic one (Exception). To me that's (usually) an anti-pattern. --S -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/19/2016 10:51 PM, Stephen Hansen wrote: But that's a fuzzy question, there's no solid and clear answer. Did you see Ethan's response? I largely agree with his trinity: On Sun, Apr 17, 2016, at 10:26 PM, Ethan Furman wrote: I sanity check for three reasons: 1) raise a nicer error message 2) keep the point of failure close to the error 3) the consequences of bad data are Bad Bad Things (tm) With a 4)th that exceptions aren't for users, only programmers. But ultimately, I'd rather a user see an exception if something weird goes wrong because they can send it to me and I can diagnose it and push an update. So I also: 4) Attempt to make sure all user errors result in user error messages, not exceptions. Note, 1) doesn't mean I always raise a nicer message, it means if "KeyError" is ambiguious or odd, I raise a better and more informative one. But you're getting nothing swapping out KeyError for Exception(lotsofwords). I use 1) more to be less 'nicer' and more, er, 'more specific'. Since I don't like exceptions to rise to the user level where niceness is needed. Yeah, that's a better phrasing for (1); I meant more appropriate or informative, such as swapping an internal error (such as KeyError) for a more meaningful FieldNotFound error (or whatever) -- largely library code concerns. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, Apr 17, 2016, at 12:34 PM, Christopher Reimer wrote: > if color not in [VARS['COLOR_BLACK'], VARS['COLOR_WHITE']]: > raise Exception("Require \'{}\' or \'{}\' for input value, got > \'{}\' instead.".format(VARS['COLOR_BLACK'], VARS['COLOR_WHITE'], color)) Do you think it likely you'll receive a 'color' value not in the list of black and white? Are you accepting colors from users? If you are, I'd sanity check *at user input*. Users are crazy, sanitize and check the heck out of their stuff. Your code, though? Your time and effort is better spent putting in a docstring documenting what's valid in color, and if some other coder puts in red, why, they'll get a KeyError, and it'll point to precisely what line is wrong, and be able to figure it out. Unit tests are where you try feeding invalid data into functions and see how they react-- and the correct reaction to bad data is usually exceptions. In this case, a KeyError thrown by [VARS['COLOR_BLACK'], VARS['COLOR_WHITE']][color] is more descriptive then your verbose Exception. (What's with the VARS business? Something smells bad there. You're doing something weird there) > How much sanity checking is too much in Python? IMHO, you've got too much. But that's a fuzzy question, there's no solid and clear answer. Did you see Ethan's response? I largely agree with his trinity: On Sun, Apr 17, 2016, at 10:26 PM, Ethan Furman wrote: > I sanity check for three reasons: > > 1) raise a nicer error message > > 2) keep the point of failure close to the error > > 3) the consequences of bad data are Bad Bad Things (tm) With a 4)th that exceptions aren't for users, only programmers. But ultimately, I'd rather a user see an exception if something weird goes wrong because they can send it to me and I can diagnose it and push an update. So I also: 4) Attempt to make sure all user errors result in user error messages, not exceptions. Note, 1) doesn't mean I always raise a nicer message, it means if "KeyError" is ambiguious or odd, I raise a better and more informative one. But you're getting nothing swapping out KeyError for Exception(lotsofwords). I use 1) more to be less 'nicer' and more, er, 'more specific'. Since I don't like exceptions to rise to the user level where niceness is needed. --Stephen m e @ i x o k a i . i o -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Tue, Apr 19, 2016 at 11:23 PM Christopher Reimer < christopher_rei...@icloud.com> wrote: > On 4/19/2016 1:02 AM, Michael Selik wrote: > > > Why relocate rather than remove? What message would you provide that's > > better than ``KeyError: 42`` with a traceback that shows exactly which > > dictionary is being used and how? > > I think you misread my code. No dictionary exception occurs in the > sanity checks. Below is the full function with the revised sanity check > for positions that compares the input list with the two valid lists of > board positions. > Perhaps I did misread it. What is the purpose of the "sanity check"? If it's not obvious I suggest revising the code rather than adding comments. The first time I read your code, I thought the check was designed to avoid the possibility of a KeyError a few lines later. My suggestion was to simply allow bad inputs to cause KeyErrors and not clutter your code. This second time I'm reading, it seems to be a sort of boundary check, but using ``in`` which would cause a bug... Did you mean to use an inequality? > > I meant, what goes wrong if the number of positions input is other than > > 16? Without these "sanity" checks, your functions might be reusable in, > > say, a checkers game. > > I have no desire to write reusable code for two > similar but different games at the same time. > Reusability is a nice side-effect of fewer "sanity checks". Other goals are clarity, efficiency, and productivity. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Wed, Apr 20, 2016 at 12:20 PM, Christopher Reimerwrote: > I think you misread my code. No dictionary exception occurs in the sanity > checks. Below is the full function with the revised sanity check for > positions that compares the input list with the two valid lists of board > positions. > > > def generate_set(color, positions): > > if positions not in [VARS['COORDINATES'][VARS['BOARD_BOTTOM']], > VARS['COORDINATES'][VARS['BOARD_TOP']]]: > raise Exception("List for positions contains no valid coordinates, " > "got {} instead.".format(positions)) > > # generate objects according to color and position > for position in positions: > rank, file = position > if rank in VARS['RANK_NOBILITY']: > if file in VARS['FILE_ROOK']: > yield Rook(color, position) > elif file in VARS['FILE_BISHOP']: > yield Bishop(color, position) > elif file in VARS['FILE_KNIGHT']: > yield Knight(color, position) > elif file is VARS['FILE_QUEEN']: > yield Queen(color, position) > elif file is VARS['FILE_KING']: > yield King(color, position) > else: > yield Pawn(color, position) > If you nuke the check at the beginning, what happens? (By the way, I don't like this shouty "VARS" thing you have going on. It makes it hard to skim the code. I'm not entirely sure what your initial "not in" check is even doing.) You seem to have two slightly different ways of checking things: first something about BOARD_TOP and BOARD_BOTTOM, and then something else about RANK_NOBILITY and... everything else. It looks to me like all you need is to have a second check for RANK_PAWNS, and then raise an exception if it's neither of those. Then you don't need to pre-check, and the rules aren't split into two places. But if I were doing this, I'd make it far more data-driven. starting_positions = { VARS['FILE_ROOK']: Rook, VARS['FILE_BISHOP']: Bishop, ... } Or, even better, tie that to the definitions of your classes, in some way. (Metaprogramming is great here.) Then your code doesn't need an if/elif tree; you can generate starting positions easily by just looking up your table. BTW, it's usually best to not raise Exception, but a custom subclass of it. But I'm going to assume that this is just an example. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/19/2016 1:02 AM, Michael Selik wrote: Why relocate rather than remove? What message would you provide that's better than ``KeyError: 42`` with a traceback that shows exactly which dictionary is being used and how? I think you misread my code. No dictionary exception occurs in the sanity checks. Below is the full function with the revised sanity check for positions that compares the input list with the two valid lists of board positions. def generate_set(color, positions): if positions not in [VARS['COORDINATES'][VARS['BOARD_BOTTOM']], VARS['COORDINATES'][VARS['BOARD_TOP']]]: raise Exception("List for positions contains no valid coordinates, " "got {} instead.".format(positions)) # generate objects according to color and position for position in positions: rank, file = position if rank in VARS['RANK_NOBILITY']: if file in VARS['FILE_ROOK']: yield Rook(color, position) elif file in VARS['FILE_BISHOP']: yield Bishop(color, position) elif file in VARS['FILE_KNIGHT']: yield Knight(color, position) elif file is VARS['FILE_QUEEN']: yield Queen(color, position) elif file is VARS['FILE_KING']: yield King(color, position) else: yield Pawn(color, position) I meant, what goes wrong if the number of positions input is other than 16? Without these "sanity" checks, your functions might be reusable in, say, a checkers game. Chess has 16 pieces (six types) on each side that are set up on the board in a particular order. Checkers has 12 pieces (one type) on each side that are set up on alternating squares in no particular order. Since I'm writing a chess engine because it has endless supply of programming changes, I have no desire to write reusable code for two similar but different games at the same time. Thanks, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Mon, Apr 18, 2016 at 1:05 AM Christopher Reimer < christopher_rei...@icloud.com> wrote: > On 4/17/2016 3:18 PM, Michael Selik wrote: > > > I'd rather turn the question around: how much sanity checking is > > necessary or useful? You'll find the answer is "surprisingly little" > > compared to your experience in Java. > > I'm looking for a pythonic approach to sanity checking. From what I read > elsewhere, sanity checking belongs in the unit tests and/or library > classes designed for other people to use. I haven't seen many examples > of sanity checks that is common in Java. > > > For example, you don't need to > > explicitly check whether the color is present in your dictionary, > > because it'll give you a KeyError if you look up a bad key. > > Without the sanity check against the constant dictionary, the color > variable could be anything (it should be a string value). Looking at the > code again, I should relocate the sanity checks in the Piece base class. > Why relocate rather than remove? What message would you provide that's better than ``KeyError: 42`` with a traceback that shows exactly which dictionary is being used and how? > Why does the len of positions need to be 16? > > The positions variable is list of coordinates for 16 chess pieces (eight > pawns, two rooks, two knights, two bishops, a king and a queen) for each > color, locating the pieces on either the bottom quarter (i.e., [(1,1), > ..., (2,8)]) or the top quarter (i.e., [(7,1), ..., (8,8)]) of the board. > I meant, what goes wrong if the number of positions input is other than 16? Without these "sanity" checks, your functions might be reusable in, say, a checkers game. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 04/17/2016 12:34 PM, Christopher Reimer wrote: How much sanity checking is too much in Python? What happens if your extensive sanity checks turn up a bug? In Python the usual answer is you raise an error: raise ValueError('blahblah not a valid color') What happens if you don't sanity check anything and the wrong color is passed in? Python will raise an error for you: Traceback ... KeyError: 'blahblah' not found --- I sanity check for three reasons: 1) raise a nicer error message 2) keep the point of failure close to the error 3) the consequences of bad data are Bad Bad Things (tm) If none of those apply, I don't bother sanity checking. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On 4/17/2016 3:18 PM, Michael Selik wrote: I'd rather turn the question around: how much sanity checking is necessary or useful? You'll find the answer is "surprisingly little" compared to your experience in Java. I'm looking for a pythonic approach to sanity checking. From what I read elsewhere, sanity checking belongs in the unit tests and/or library classes designed for other people to use. I haven't seen many examples of sanity checks that is common in Java. For example, you don't need to explicitly check whether the color is present in your dictionary, because it'll give you a KeyError if you look up a bad key. Without the sanity check against the constant dictionary, the color variable could be anything (it should be a string value). Looking at the code again, I should relocate the sanity checks in the Piece base class. Why does the len of positions need to be 16? The positions variable is list of coordinates for 16 chess pieces (eight pawns, two rooks, two knights, two bishops, a king and a queen) for each color, locating the pieces on either the bottom quarter (i.e., [(1,1), ..., (2,8)]) or the top quarter (i.e., [(7,1), ..., (8,8)]) of the board. Thanks, Chris R. -- https://mail.python.org/mailman/listinfo/python-list
Re: How much sanity checking is required for function inputs?
On Sun, Apr 17, 2016, 4:35 PM Christopher Reimer < christopher_rei...@icloud.com> wrote: > Greetings, > > I'm currently building a chess engine to learn the finer details of > Python. When I learned all flavors of Java in community college a decade > ago, we had to sanity check the hell out of the input values for every > function and wrote a lot of redundant code in addition to the > getters/setters code. > > Here's the input sanity checking I got for a generator function to > return a set of chess pieces for a specified color and position. > > > def generate_set(color, positions): > > if color not in [VARS['COLOR_BLACK'], VARS['COLOR_WHITE']]: > raise Exception("Require \'{}\' or \'{}\' for input value, got > \'{}\' instead.".format(VARS['COLOR_BLACK'], VARS['COLOR_WHITE'], color)) > > if len(positions) != 16: > raise Exception("Require 16 positions for input value, got {} > instead.".format(len(positions))) > > > The two sanity checks are fairly straight forward. Color input has to > match the color constant strings. Positions input has to have 16 items. > > I *could* sanity check the positions input to determine if it had a list > of 16 valid coordinates. The reason I don't is because the code that > calls this function builds the coordinates from constants with valid > coordinates. However, if I was doing this in my Java classes, one of my > instructors rap me on the knuckles for not sanity checking to nth degree. > > How much sanity checking is too much in Python? > I'd rather turn the question around: how much sanity checking is necessary or useful? You'll find the answer is "surprisingly little" compared to your experience in Java. For example, you don't need to explicitly check whether the color is present in your dictionary, because it'll give you a KeyError if you look up a bad key. Why does the len of positions need to be 16? > -- https://mail.python.org/mailman/listinfo/python-list
How much sanity checking is required for function inputs?
Greetings, I'm currently building a chess engine to learn the finer details of Python. When I learned all flavors of Java in community college a decade ago, we had to sanity check the hell out of the input values for every function and wrote a lot of redundant code in addition to the getters/setters code. Here's the input sanity checking I got for a generator function to return a set of chess pieces for a specified color and position. def generate_set(color, positions): if color not in [VARS['COLOR_BLACK'], VARS['COLOR_WHITE']]: raise Exception("Require \'{}\' or \'{}\' for input value, got \'{}\' instead.".format(VARS['COLOR_BLACK'], VARS['COLOR_WHITE'], color)) if len(positions) != 16: raise Exception("Require 16 positions for input value, got {} instead.".format(len(positions))) The two sanity checks are fairly straight forward. Color input has to match the color constant strings. Positions input has to have 16 items. I *could* sanity check the positions input to determine if it had a list of 16 valid coordinates. The reason I don't is because the code that calls this function builds the coordinates from constants with valid coordinates. However, if I was doing this in my Java classes, one of my instructors rap me on the knuckles for not sanity checking to nth degree. How much sanity checking is too much in Python? Thank you, Chris R -- https://mail.python.org/mailman/listinfo/python-list