Thanks to the Python data model, your user-defined types can behave as naturally as the built-in types.
Object Representation Methods
Every object-oriented language has at least one standard way of getting a string representation from any object. Python has two:
repr()
- return a string representing the object as the developer wants to see it
str()
- return a strIng representing the object as the user wants to see it
There are two additional special methods to support alternative representations of objects: __bytes__
and __format__
.
__bytes__
method is analogous to__str__
- it’s called by
bytes()
to get the object represented as a byte sequence
- it’s called by
__format__
- both the built-in function
format()
and thestr.format()
method call it to get string displays of objects using special formatting codes.
- both the built-in function
Vector Class Redux
classmethod vs staticmethod
classmethod
decorator – to define a method that operates on the class and not on instances.
- classmethod changes the way the method is called
- it receives the class itself as the first argument, instead of an instance
staticmethod
decorator – changes a method so that it receives no special first argument
In essence, a static method is just like a plain function that happens to live in a class body, instead of being defined at the module level.
klassmeth
just returns all positional argumentsstatmeth
does the same- No matter how you invoke it,
Demo.klassmeth
receives theDemo
class as the first argumentDemo.statmeth
behaves just like a plain old functions
?
啊 我怎么还是不知道这什么跟什么啊
Formatted Displays
The format()
built-in function and the str.format()
method delegate the actual formmating to each type by calling their .__format__
method.
The second callout makes an important point: a format string such as '{0.mass: 5.3e}'
actually uses two separate notations
- The
'0.mass'
to the left of the colon is thefield_name
part of the replacement field syntax - The
'5.3e'
after the colon is the formatting specifier
The notation used in the formatting specifier is called the Format Specification Mini-Language.
The Format Specification Mini-Language is extensible because each class gets to interpret the format_spec
argument as it likes.
- e.g. the classes in the
datetime
module use the same format codes in thestrftime()
functions and in their__format__
methods.
A Hashable Vector2d
Private and “Protected” Attributes in Python
Saving Space with the __slots__
Class Attribute
By default, Python stores instance attributes in a per-instance dict
named __dict__
.
dicts have a significant memory overhead because of the underlying hash table used to provide fast access.
If you are dealing with millions of instances with few attributes, the __slots__
class attribute can save a lot of memory, by letting the interpreter store the instance attributes in a tuple
instead of a dict
!!!
a__slot__
attribute inherited from a superclass has no effect.
Python only takes into account__slots__
attributes defined in each class individually.
To define __slots__
, you create a class attribute with that name and assign it an iterable of str
with identifiers for the instance attributes.
By defining __slots__
in the class, you are telling interpreter: “These are all the instance attributes in this class”. Python then stores them in a tuple-like structure in each instance, avoiding the memory overhead of the per-instance __dict__
. This can make a huge difference in memory usage if you have millions of instances active at the same time.
When
__slots__
is specified in a class, its instances will not be allowed to have any other attributes apart from those named in__slots__
.
`
The Problems with __slots__
__slots__
provide significant memory savings if properly used, but there are a few caveats:
- you must remember to redeclare
__slots__
in each sublass, because the inherited attribute is ignored by the interpreter - instances will only be able to have the attributes listed in
__slots__
, unless you include'__dict__'
in__slots__
(but doing so may negate the memory savings) - instances cannot be targets of weak references unless you remember to include
'__weakref__'
in__slots__
If your program is not handling millions of instances, it’s probably not worth the trouble of creating a somewhat unusual and tricky class whose instances may not accept dynamic attributes or may not support weak references.
Overriding Class Attributes
A distinctive feature of Python is how class attributes can be used as default values for instane attributes.
- in
Vector2d
there is thetypecode
class attribute. - the default
Vector2d.typecode
is'd'
, meaning each vector component will be represented as an 8-byte double precision float when exporting tobyte
- if set to
'f'
, each component will be exported as a 4-byte single precision float