前段时间出差,回来后又写开题报告,所以把写博客记录的事放下了(惭愧)。不如正题,坚持!
这里可以在Jupyter notebook模式下查看,效果更好
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!s},{0.y!s})'.format(self)
p = Pair(3,4)
p
Pair(3,4)
print(p)
(3,4)
p = Pair(3,4)
print('p is {0!r}'.format(p))
p is Pair(3,4)
print('p is {0}'.format(p))
p is (3,4)
# 也可以使用% 操作符
def __repr__(self):
return 'Pair(%r,%r)'%(self.x,self.y)
_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)
d = Date(2017,12,21)
format(d)
'2017-12-21'
format(d,'mdy')
'12/21/2017'
format(d,'dmy')
'21/12/2017'
'the data is {:ymd}'.format(d)
'the data is 2017-12-21'
'the date is {:dmy}'.format(d)
'the date is 21/12/2017'
from datetime import date
d = date(2012,9,12)
d
datetime.date(2012, 9, 12)
format(d)
'2012-09-12'
format(d,'%A,%B,%d,%Y')
'Wednesday,September,12,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
# 该类的特点是他表示了一个网络的连接,但是初始化的时候并不会做任何事情
# (比如他并没有建立一个连接),连接的建立和关闭是使用with语句自动完成的
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.pyhton.org\r\n')
s.send(b'\r\n')
resp = b''.join(iter(partial(s.recv,8192),b''))
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 = []
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
# 应用
from functools import partial
conn = LazyConnection(('www.python.org',80))
with conn as s1:
pass
with conn as s2:
pass
class Data:
__slots__ = ['year', 'month', 'day']
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
class A:
def __init__(self):
self._internal = 0 #内部属性
self.public = 1 #外部属性
def public_method(self):
'''公有方法'''
pass
def _internal_method(self):
'''内部方法'''
pass
class B:
def __init__(self):
self.__private = 0 #私有属性
def __private_method(self): #私有方法
pass
def public_method(self):
pass
class C(B):
def __init__(self):
super().__init__()
self.__private = 1# 并不会覆盖B.__private
#并不会覆盖B.__private_method
def __private_method(self):
pass
lambda_ = 2.0
class Person:
def __init__(self, first_name):
self.first_name = first_name
#Getter function
@property
def first_name(self):
return self._first_name
#Setter function
@first_name.setter
def first_name(self,value):
if not isinstance(value, str):
raise TypeError("Expected a string")
self._first_name = value
#Deleter function
@first_name.deleter
def first_name(self):
raise AttributeError("can't delete attribute")
a = Person('Guido')
a.first_name
'Guido'
a.first_name = 12 #应该赋值为一个字符串
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
----> 1 a.first_name = 12 #应该赋值为一个字符串
in first_name(self, value)
11 def first_name(self,value):
12 if not isinstance(value, str):
---> 13 raise TypeError("Expected a string")
14 self._first_name = value
15
TypeError: Expected a string
a.first_name = 'Jack'
a.first_name
'Jack'
del a.first_name
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in ()
----> 1 del a.first_name
in first_name(self)
17 @first_name.deleter
18 def first_name(self):
---> 19 raise AttributeError("can't delete attribute")
20
AttributeError: can't delete attribute
p = Person('Guido')
p.get_first_name()
'Guido'
p.set_first_name('Jjldik')
p.get_first_name()
'Jjldik'
class Person:
def __init__(self,first_name):
self.set_first_name(first_name)
#getter function
def get_first_name(self):
return self._first_name
#Setter function
def set_first_name(self, value):
if not isinstance(value, str):
raise TypeError('Expected a string')
self._first_name = value
#Deleter function
def del_first_name(self):
raise AttributeError("can't delete attribute")
# make a property from a existing get/set memthods
name = property(get_first_name,set_first_name,del_first_name)
一个 property 属性其实就是一系列相关绑定方法的集合。如果你去查看拥有
property 的类,就会发现 property 本身的 fget、 fset 和 fdel 属性就是类里面的普通方
法。
注意:只有在你确实需要对属性进行额外的操作时才应该使用property
Properties还是一种定义动态计算attribute的方法,这种attributes并不会被实际存储,而是在需要的时候计算出来
import math
class Circle:
def __init__(self,radius):
self.radius = radius
@property
def area(self):
return math.pi * self.radius * self.radius
@property
def diameter(self):
return self.radius * 2
@property
def perimeter(self):
return 2 * math.pi * self.radius
c = Circle(4.0)
c.area
50.26548245743669
c.diameter
8.0
c.perimeter
25.132741228718345
class A:
def spam(self):
print('A.spam')
class B(A):
def spam(self):
print('B.spam')
super().spam()
class A:
def __init__(self):
self.x = 0
class B(A):
def __init__(self):
super()._init__()
self.y = 1
class Proxy:
def __init__(self, obj):
self.obj = obj
def __getattr__(self, name):
return getattr(self._obj, name)
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
else:
setattr(self._obj, name, value)
class Base:
def __init__(self):
print('Base.__init__()')
class A(Base):
def __init__(self):
Base.__init__(self)
print('A.__init__()')
class Base:
def __init__(self):
print('Base.__init__()')
class A(Base):
def __init__(self):
Base.__init__(self)
print('A.__init__()')
class B(Base):
def __init__(self):
Base.__init__(self)
print('B.__init__()')
class C(A,B):
def __init__(self):
A.__init__(self)
B.__init__(self)
print('C.__init__()')
# 调用上述代码会发现Base.__init__()调用了两次
c = C()
Base.__init__()
A.__init__()
Base.__init__()
B.__init__()
C.__init__()
class Base:
def __init__(self):
print('Base.__init__()')
class A(Base):
def __init__(self):
super().__init__()
print('A.__init__()')
class B(Base):
def __init__(self):
super().__init__()
print('B.__init__()')
class C(A,B):
def __init__(self):
super().__init__()
print('C.__init__()')
c = C()
Base.__init__()
B.__init__()
A.__init__()
C.__init__()
C.__mro__
(__main__.C, __main__.A, __main__.B, __main__.Base, object)
为了实现继承, Python 会在 MRO 列表上从左到右开始查找基类,直到找到第一
个匹配这个属性的类为止
遵循三个准则:
1> 子类先于父类被检查
2> 多个父类会根据它们在列表中的顺序被检查
3> 如果对下一个类存在两个合法的选择,选择第一个父类
super() 有个令人吃惊的地方是它并不一定去查找某个类在 MRO 中下一个直接
父类,你甚至可以在一个没有直接父类的类中使用它。
class A :
def spam(self):
print('A.spam')
super().spam()
#直接使用这个类会出错
a = A()
a.spam()
A.spam
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in ()
1 #直接使用这个类会出错
2 a = A()
----> 3 a.spam()
in spam(self)
2 def spam(self):
3 print('A.spam')
----> 4 super().spam()
AttributeError: 'super' object has no attribute 'spam'
# 但是多继承时会正常
class B:
def spam(self):
print('B.spam')
class C(A, B):
print('C.spam')
c = C()
c.spam()
C.spam
A.spam
B.spam
C.__mro__
(__main__.C, __main__.A, __main__.B, object)