diff --git a/publish b/publish index 680a290..bc24aa5 100755 --- a/publish +++ b/publish @@ -4,6 +4,7 @@ rm -rf build mkdir build cp robots.txt *.js *.css build/ +rm examples/*.pyc cp -R examples build/ # minimize HTML (note: this script is quite fragile and relies on knowledge of how I write HTML) diff --git a/special-method-names.html b/special-method-names.html index 8c1e874..7f3f231 100644 --- a/special-method-names.html +++ b/special-method-names.html @@ -69,14 +69,6 @@ td a:link, td a:visited{border:0}
  • By convention, format_spec should conform to the Format Specification Mini-Language. - -

    Classes That Act Like Iterators

    In the Iterators chapter, you saw how to build an iterator from the ground up using the __iter__() and __next__() methods. @@ -105,12 +97,6 @@ __format__

  • The __reversed__() method is uncommon. It takes an existing sequence and returns an iterator that yields the items in the sequence in reverse order, from last to first. - -

    Computed Attributes

    FIXME not sure of the wording/depth required here because I don't yet know if I'm going to cover these in a previous chapter. Let's assume I'm not, and I can move the examples later if need be. @@ -143,10 +129,10 @@ __reversed__ - covered in ordereddict.py

    1. If your class defines a __getattribute__() method, Python will call it on every reference to any attribute or method name (except special method names, since that would cause an unpleasant infinite loop). -
    2. If your class defines a __getattr__() method, Python will call it only after looking for the attribute in all the normal places. If an instance x defines an attribute foo, x.foo will not call x.__getattr__("foo"); it will simply return the already-defined value of x.foo. +
    3. If your class defines a __getattr__() method, Python will call it only after looking for the attribute in all the normal places. If an instance x defines an attribute color, x.color will not call x.__getattr__("color"); it will simply return the already-defined value of x.color.
    4. The __setattr__() method is called whenever you assign a value to an attribute.
    5. The __delattr__() method is called whenever you delete an attribute. -
    6. The __dir__() method is useful if you define a __getattr__() or __getattribute__() method. Normally, calling dir(x) would only list the regular attributes and methods. If your __getattr()__ method handles a foo attribute dynamically, dir(x) would not list foo as one of the available attributes. Overriding the __dir__() method allows you to list foo as an available attribute, which is helpful for other people who wish to use your class without digging into the internals of it. +
    7. The __dir__() method is useful if you define a __getattr__() or __getattribute__() method. Normally, calling dir(x) would only list the regular attributes and methods. If your __getattr()__ method handles a color attribute dynamically, dir(x) would not list color as one of the available attributes. Overriding the __dir__() method allows you to list color as an available attribute, which is helpful for other people who wish to use your class without digging into the internals of it.

    The distinction between the __getattr__() and __getattribute__() methods is subtle but important. I can explain it with two examples: @@ -154,22 +140,22 @@ __reversed__ - covered in ordereddict.py

     >>> class Dynamo:
     ...   def __getattr__(self, key):
    -...     if key == "foo":                        
    -...       return "Hi, I'm a custom value."
    +...     if key == "color":         
    +...       return "PapayaWhip"
     ...     else:
    -...       raise AttributeError                  
    +...       raise AttributeError     
     ... 
     >>> dyn = Dynamo()
    ->>> dyn.foo                                     
    -"Hi, I'm a custom value."
    ->>> dyn.foo = "Overridden!"
    ->>> dyn.foo                                     
    -'Overridden!'
    +>>> dyn.color +'PapayaWhip' +>>> dyn.color = "LemonChiffon" +>>> dyn.color +'LemonChiffon'
      -
    1. The attribute name is passed into the __getattr()__ method as a string. If the name is "foo", the method returns a value. (In this case, it’s just a hard-coded string, but you would normally do some sort of computation and return the result.) +
    2. The attribute name is passed into the __getattr()__ method as a string. If the name is "color", the method returns a value. (In this case, it’s just a hard-coded string, but you would normally do some sort of computation and return the result.)
    3. If the attribute name is unknown, the __getattr()__ method needs to raise an AttributeError exception, otherwise your code will silently fail when accessing undefined attributes. (Technically, if the method doesn’t raise an exception or explicitly return a value, it returns None, the Python null value. This means that all attributes not explicitly defined will be None, which is almost certainly not what you want.) -
    4. The dyn instance does not have an attribute named foo, so the __getattr__() method is called to provide a computed value. -
    5. After explicitly setting dyn.foo, the __getattr__() method will no longer be called to provide a value for dyn.foo, because dyn.foo is already defined on the instance. +
    6. The dyn instance does not have an attribute named color, so the __getattr__() method is called to provide a computed value. +
    7. After explicitly setting dyn.color, the __getattr__() method will no longer be called to provide a value for dyn.color, because dyn.color is already defined on the instance.

    On the other hand, the __getattribute__() method is absolute and unconditional. @@ -177,35 +163,26 @@ __reversed__ - covered in ordereddict.py

     >>> class SuperDynamo:
     ...   def __getattribute__(self, key):
    -...     if key == 'foo':
    -...       return "Hi, I'm a custom value."
    +...     if key == 'color':
    +...       return "PapayaWhip"
     ...     else:
     ...       raise AttributeError
     ... 
     >>> dyn = SuperDynamo()
    ->>> dyn.foo                                     
    -"Hi, I'm a custom value."
    ->>> dyndyn.foo = "Overridden!"
    ->>> dyn.foo                                     
    -"Hi, I'm a custom value."
    +>>> dyn.color +"PapayaWhip" +>>> dyn.color = "LemonChiffon" +>>> dyn.color +"PapayaWhip"
      -
    1. The __getattribute__() method is called to provide a value for dyn.foo. -
    2. After explicitly setting dyn.foo, the __getattribute__() method is still called to provide a value for dyn.foo. If present, the __getattribute__() method is called unconditionally for every attribute and method lookup, even for attributes that you explicitly set after creating an instance. +
    3. The __getattribute__() method is called to provide a value for dyn.color. +
    4. Even after explicitly setting dyn.color, the __getattribute__() method is still called to provide a value for dyn.color. If present, the __getattribute__() method is called unconditionally for every attribute and method lookup, even for attributes that you explicitly set after creating an instance.

    If your class defines a __getattribute__() method, you probably also want to define a __setattr__() method and coordinate between them to keep track of attribute values. Otherwise, any attributes you set after creating an instance will disappear into a black hole.

    - - -

    Classes That Act Like Functions

    FIXME @@ -267,13 +244,6 @@ __dir__ x.__missing__("nonexistent_key") - -

    Classes That Act Like Numbers

    Using the appropriate special methods, you can define your own classes that act like numbers. That is, you can add them, subtract them, and perform other mathematical operations on them. This is how fractions are implemented — the Fraction class implements these special methods, then you can do things like this: @@ -345,22 +315,6 @@ __missing__ (*) x.__or__(y) - -

    That’s all well and good if x is an instance of a class that implements those methods. But what if it doesn’t implement one of them? Or worse, what if it implements it, but it can’t handle certain kinds of arguments? For example:

    @@ -439,21 +393,6 @@ __or__
     y.__ror__(x)
     
     
    -
    -
     

    But wait! There’s more! If you’re doing “in-place” operations, like x /= 3, there are even more special methods you can define. @@ -511,21 +450,6 @@ __ror__
    x.__ior__(y)
    - -

    Note: for the most part, the in-place operation methods are not required. If you don’t define an in-place method for a particular operation, Python will try the methods. For example, to execute the expression x /= y, Python will:

      @@ -597,21 +521,6 @@ __ior__ x.__index__() - -

      Classes That Can Be Compared

      I broke this section out from the previous one because comparisons are not strictly the purview of numbers. Many datatypes can be compared — strings, lists, even dictionaries. If you’re creating your own class and it makes sense to compare your objects to other objects, you can use the following special methods to implement comparisons. @@ -651,18 +560,6 @@ __index__ x.__bool__() - -

      Classes That Can Be Pickled