python_cookbook记录

类与对象

2017-08-30  本文已影响0人  buildbody_coder

类与对象

改变对象字符串显示

class Pair:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Pair({0.x!r}, {0.y!r})'.format(self)

    def __str__(self):
        return '({0.x!r}, {0.y!r})'.format(self)
out:
p = Pair(3, 4)
>>> p #repr
Pair(3, 4) 
>>> print (p) #str
(3, 4)

通过format()函数自定义字符串的格式化

_formats = {
    '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, code):
        if code == '':
            code = 'ymd'
        fmt = _formats[code]
        return fmt.format(d=self)
out:
d = date(2012, 12, 21)
>>> format(d)
'2012-12-21'
>>> format(d, 'mdy')
'12/21/2012'

让对象支持上下文管理器

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

if __name__ == '__main__':
    from functools import partial
    conn = LazyConnection(('www.python.org', 80))
    with conn as s:
        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''))
        print (resp)

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.connections = list()

    def __enter__(self):
        sock = socket(self.family, self.type)
        sock.connect(self.address)
        self.connections.append(sock)
        return sock

    def __exit__(self, exc_ty, exc_val, tb):
        self.connections.pop().close()

if __name__ == '__main__':
    from functools import partial
    conn = LazyConnection(('www.python.org', 80))
    with conn as s1:
        pass
        with conn as s2:
            pass

在类中对属性进行封装

class A:
    def __init__(self):
        self._internal = 0
        self.public = 1

    def public_method(self):
        pass
    def _initernal_method(self):
        pass
class B:
    def __init__(self):
        self.__private = 0

    def __private_method(self):
        pass
    def public_mechod(self):
        pass
        self.__private_method()

class C(B):
    def __init__(self):
        super().__init__()
        self.__private = 1

    def __private_method(self):
        pass
lambda_ = 2.0

创建可管理的属性

class Person:
    def __init__(self, first_name):
        self.first_name = first_name

    @property
    def first_name(self):
        return self._first_name

    @first_name.setter
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Exceped a string')
        self._first_name = value

    @first_name.deleter
    def first_name(name):
        raise AttributeError("Can't delete attribute")
>>> a = Person('Guido')
>>> a.first_name
'Guido'
>>> a.first_name = 'Bob'
>>> a.first_name
'Bob'

调用父类的方法

class A:
    def spam(self):
        print ('A.spam')

class B(A):
    def spam(self):
        print ('B.spam')
        super().spam()
out:
>>> b = B()
>>> b.spam()
B.spam
A.spam
class A:
    def __init__(self):
        self.x = 0

class B(A):
    def __init__(self):
        super().__init__()
        self.y = 1

简化数据结构的初始化

import math
class Structure1:
    _fields = []
    def __init__(self, *args):
        if len(args) != len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
        for name, value in zip(self._fields, args):
            #self.name = value
            setattr(self, name, value)

class Stock(Structure1):
    _fields = ['name', 'shares', 'price']

class Point(Structure1):
    _fields = ['x', 'y']

class Circle(Structure1):
    _fields = ['radius']

    def area(self):
        return math.pi * self.radius ** 2
out:
>>> s = Stock('ACME', 50, 91.1)
>>> p = Point(2, 3)
>>> c = Circle('ACME', 50)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    c = Circle('ACME', 50)
  File "/Users/gongyulei/code_example/python_example/cookbook/ch8/ch8_11.py", line 11, i
n __init__
    raise TypeError('Expected {} arguments'.format(len(self._fields)))
TypeError: Expected 1 arguments
>>> s.shares
50
class Structure2:
    _fields = []
    def __init__(self, *args, **kwargs):
        if len(args) > len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
        for name, value in zip(self._fields, args):
            #self.name = value
            setattr(self, name, value)

        for name in self._fields[len(args):]:
            setattr(self, name, kwargs.pop(name))

        if kwargs:
            raise TypeError('Invalid argument(s):{}'.format(',', join(kwargs)))

if __name__ == '__main__':
    class Stock(Structure2):
        _fields = ['name', 'shares', 'price']
    s1 = Stock('ACME', 50, 91.1)
    s2 = Stock('ACME', shares=91.1, price=91.1)
class Structure3:
    _fields = []
    def __init__(self, *args, **kwargs):
        if len(args) != len(self._fields):
            raise TypeError('Expected {} arguments'.format(len(self._fields)))
        for name, value in zip(self._fields, args):
            #self.name = value
            setattr(self, name, value)

        extra_args = kwargs.keys() - self._fields
        for name in extra_args:
            setattr(self, name, kwargs.pop(name))

        if kwargs:
            raise TypeError('Invalid argument(s):{}'.format(',', join(kwargs)))

if __name__ == '__main__':
    class Stock(Structure3):
            _fields = ['name', 'shares', 'price']

        s1 = Stock('ACME', 50, 91.1, date='8/2/2012')

实现自定义容器

>>> import collections
>>> collections.Sequence()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    collections.Sequence()
TypeError: Can't instantiate abstract class Sequence with abstract methods __getitem__, 
__len__
import bisect
import collections

class SortedItems(collections.Sequence):
    def __init__(self, initila=None):
        self._items = sorted(initila) if initila is not None else []

    def __getitem__(self, index):
        return self._items[index]

    def __len__(self):
        return len(self._items)

    def add(self, item):
        #在插入的时候进行排序
        bisect.insort(self._items, item)

if __name__ == '__main__':
    items = SortedItems([5, 1, 3])
    print (list(items))
    print (items[0], items[-1])
    items.add(2)
    print (list(items))
out:
[1, 3, 5]             
1 5                   
[1, 2, 3, 5]  
>>> from ch8_14 import SortedItems
>>> import collections
>>> items = SortedItems()
>>> isinstance(items, collections.Sequence)
True
class Items(collections.MutableSequence):
    def __init__(self, initial=None):
        self._items = list(initial) if initial is not None else []

    def __getitem__(self, index):
        print ('Getting:', index)
        return self._items[index]

    def  __setitem__(self, index, value):
        print ('Setting:', index, value)
        self._itmes[index] = value

    def __delitem__(self, index):
        print ('Deleting', index)
        del self._itmes[index]

    def insert(self, index, value):
        print ('Inserting', index, value)
        self._items.insert(index, value)

    def __len__(self):
        print ('Len')
        return len(self._items)

out:
>>> a = Items([1, 2, 3])
>>> len(a)
Len
3
>>> a.append(4)
Len
Inserting 3 4
>>> a[0]
Getting: 0
1

属性的代理访问

class A:
    def spam(self, x):
        pass
    def foo(self):
        pass

class B1:
    def __init__(self):
        self._a = A()

    def spam(self, x):
        return self._a.spam(x)

    def foo(self):
        return self._a.foo()

    def bar(self):
        pass
class B2:
    def __init__(self):
        self._a = A()

    def bar(self):
        pass

    def __getattr__(self, name):
        #self._a.name
        return getattr(self._a, name)
out:
>>> from ch8_15 import B2
>>> b = B2()
>>> b.bar()
>>> b.spam(42)
class Proxy:
    def __init__(self, obj):
        self._obj = obj

    def __getattr__(self, name):
        print ('getattr:', name)
        return getattr(self._obj, name)

    def __setattr__(self, name, value):
        if name.startswith('_'):
            super().__setattr__(name, value)
        else:
            print ('setattr:', name, value)
            setattr(self._obj, name, value)

    def __delattr__(self, name):
        if name.startswith('_'):
            super().__delattr__(name)
        else:
            print ('delattr:', name)
            setattr(self._obj, name)

class spam:
    def __init__(self, x):
        self.x = x

    def bar(self, y):
        print ('Spam.bar:', self.x, y)


if __name__ == '__main__':
    s = spam(2)
    p = Proxy(s)
    print (p.x)
    p.bar(3)
    p.x = 37

在类中定义多个构造器(实现init)

import time
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @classmethod
    def today(cls):
        t = time.localtime()
        return cls(t.tm_year, t.tm_mon, t.tm_mday)
out:
>>> a = Date(2012, 12, 21)
>>> b = Date.today()
>>> b.day
30

不通过init方法初始化实例

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

if __name__ == '__main__':
    data = {'year':2012, 'month':8, 'day':29}
    d = Date.__new__(Date)
    for key, value in data.items():
        setattr(d, key, value)

实现状态机,避免过多的条件判断

class ConnectionState:
    @staticmethod
    def read(conn):
        raise NotImplementedError()

    @staticmethod
    def write(conn, data):
        raise NotImplementedError()

    @staticmethod
    def open(conn):
        raise NotImplementedError()

    @staticmethod
    def close(conn):
        raise NotImplementedError()

class ClosedConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        raise RuntimeError('Not open')

    @staticmethod
    def write(conn, data):
        raise RuntimeError('Not open')

    @staticmethod
    def open(conn):
        conn.new_state(OpenConnectionState)

    @staticmethod
    def close(conn):
        raise RuntimeError('Already closed')

class OpenConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        print ('reading')

    @staticmethod
    def write(conn, data):
        print ('writing')

    @staticmethod
    def open(conn):
        raise RuntimeError('Already open')

    @staticmethod
    def close(conn):
        conn.new_state(ClosedConnectionState)

class Connection:

    def __init__(self):
        self.new_state(ClosedConnectionState)

    def new_state(self, newstate):
        self._state = newstate

    def read(self):
        return self._state.read(self)

    def write(self, data):
        return self._state.write(self, data)

    def open(self):
        return self._state.open(self)

    def close(self):
        return self._state.close(self)


>>> c = Connection()
>>> c._state
<class 'ch8_19.ClosedConnectionState'>
>>> c.read()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    c.read()
  File "/Users/gongyulei/code_example/python_example/cookbook/ch8/ch8_19.py", line 16, i
n read
    return self._state.read(self)
  File "/Users/gongyulei/code_example/python_example/cookbook/ch8/ch8_19.py", line 47, i
n read
    raise RuntimeError('Not open')
RuntimeError: Not open
>>> c.open()
>>> c._state
<class 'ch8_19.OpenConnectionState'>
>>> c.write('hello')
writing
>>> c.close()
>>> c._state
<class 'ch8_19.ClosedConnectionState'>

通过字符串调用对象的方法

import math
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance(self, x, y):
        return math.hypot(self.x - x, self.y - y)
out:
>>> p = Point(2, 3)
>>> d = getattr(p, 'distance')(0, 0)
>>> d
3.605551275463989
>>> d = getattr(p, 'distance')
>>> d
<bound method Point.distance of <ch8_20.Point object at 0x109815438>>
上一篇 下一篇

猜你喜欢

热点阅读