This chapter is a bit of advance for the contents of the following classes .
all Python The objects of are all extended PyObject,python The garbage collection mechanism of is to calculate references , This object defines py_ssize Is used to do this . A type object can be understood as a custom object class. stay Python The functions in are all generic pointers , So you can go through PyObject Of ob_type Property to determine the actual type , This is also a manifestation of polymorphism .
stay Python The garbage collection mechanism in is quite special , It uses the memory object pool technology , The space freed by the object is returned to the memory pool , If it is reused, it can be obtained from the memory pool. If it is no longer used, it can be recycled , And java More similar . All built-in objects have their own object buffer pool mechanism . The objects in this buffer pool are immutable , The objects in the pool are shared , But it will not cause the problem of multiple concurrency .
class FormatChange:
def __init__( self, x, y):
self. x = x
self. y = y
def __repr__( self):
return f'use repr method: ({ self. x} , { self. y} )'
def __str__( self):
return f'use str method: ({ self. x} , { self. y} )'
fc = FormatChange( 5, 7)
print( fc. __repr__()) # use repr method: (5, 7)
print( fc) # use str method: (5, 7)
print( f'fc is { fc ! r} ') #!r To express with repr Methods to replace str Method output
format_dict = {
'ymd': '{d.year}-{d.month}-{d.day}',
'mdy': '{d.month}/{d.day}/{d.year}',
'dmy': '{d.day}/{d.month}/{d.year}'
}
class Date:
def __init__( self, year, month, day):
self. year = year
self. month = month
self. day = day
def __format__( self, format_type = 'ymd'):
#format_type: Format type , By default ymd The way
if not format_type:
format_type = 'ymd'
fmt = format_dict[ format_type]
return fmt. format( d = self) # there format It's a hook function
curr_data = Date( 2020, 5, 6)
# This actually calls format Is a method in a class library , Then the custom overridden... Is called in reverse format Method
print( f'default format: { format( curr_data)} ') #2020-5-6
print( f"use mdy format: { format( curr_data, 'mdy')} ") #5/6/2020
use slots Objects created , Its memory usage will be reduced 2/3 about . But the drawback is that you can't add new attributes to the object , Nor can inheritance be implemented , So it is usually only used as a memory optimization tool , Used to store large amounts of data .
class Date:
__slots__ = [ 'year', 'month', 'day']
def __init__( self, year, month, day):
self. year = year
self. month = month
self. day = day
import math
class Point:
def __init__( self, x, y):
self. x = x
self. y = y
def __repr__( self):
return f'Point({ self. x ! r:} ,{ self. y ! r:} )'
def distance( self, x, y):
return math. hypot( self. x - x, self. y - y)
# The first way : It doesn't feel very useful in this way , The front still has to new An object
p = Point( 2, 3)
d = getattr( p, 'distance')( 0, 0)
import operator
operator. methodcaller( 'distance', 0, 0)( p)
# When a method is called multiple times with the same parameters
points = [
Point( 1, 2),
Point( 3, 0),
Point( 10, - 3),
Point( - 5, - 7),
Point( - 1, 8),
Point( 3, 2)
]
# The second way to use it : Sort by distance from origin (0, 0)
points. sort( key = operator. methodcaller( 'distance', 0, 0))
p = Point( 3, 4)
d = operator. methodcaller( 'distance', 0, 0)
print( f'd(p) = { d( p)} ') #5.0
Need custom implementation enter and exit Method . It is generally used in tool classes such as network connection , Code placed in with Execute in statement , When there is a with when enter Method is called , The value returned is assigned to as Variable after . then with The statement in starts execution . Last exit Be carried out to do some cleaning up . stay exit Method has its own exception handling , If you ignore the exception, you can return None, If you return True Then the exception will be cleared . Here are two implementations : One is tool class , The other is to allow nested factory classes :
Simple implementation
from socket import socket, AF_INET, SOCK_STREAM
class LazyConnection:
def __init__( self, address, family = AF_INET, type = SOCK_STREAM):
self. address = address
self. family = family
self. type = type
self. sock = None
def __enter__( self):
if self. sock is not None:
raise RuntimeError( 'Already connected')
self. sock = socket( self. family, self. type)
self. sock. connect( self. address)
return self. sock
def __exit__( self, exc_ty, exc_val, tb):
self. sock. close()
self. sock = None
from functools import partial
conn = LazyConnection(( 'www.python.org', 80))
# Connection closed
with conn as s:
# conn.__enter__() executes: connection open
s. send( b'GET /index.html HTTP/1.0\r\n')
s. send( b'Host: www.python.org\r\n')
s. send( b'\r\n')
resp = b''. join( iter( partial( s. recv, 8192), b''))