补充:类名为有效的标识符,一般为多个单词组成的名称,每个单词除第一个字母大写外,其余的字母均小写
一:类对象和实例对象
例9.1(创建类对象和实例对象)
>>> class Person:
pass
>>> p = Person()
>>> print(Person, type(Person), id(Person))
<class '__main__.Person'> <class 'type'> 2096437524072
>>> print(p, type(p), id(p))
<__main__.Person object at 0x000001E81DA88BC8> <class '__main__.Person'> 2096441625544
例9.2(实例对象的创建和使用)
- Python创建实例对象的方法无须使用关键字new,而是直接像调用函数一样调用类对象并传递参数,因此类对象是可调用对象(Callable)
- 在Python内置函数中,bool、float、int、str、list、dict、set等均为可调用内置类对象
>>> c = complex(1, 2)
>>> c.conjugate()
(1-2j)
>>> c.real
1.0
二:属性
例9.3(定义实例属性)
Python变量不需要声明,可直接使用。所以建议用户在类定义的开始位置初始化类属性,或者在构造函数
__init__()
中初始化实例属性
>>> class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hi(self):
print("您好,我叫", self.name)
>>> p = Person('zgh', 18)
>>> p.say_hi()
您好,我叫 zgh
>>> print(p.age)
18
例9.4(定义类对象属性)
类属性如果通过
obj.属性名
来访问,则属于该实例地实例属性
>>> class Person:
count = 0
name = "Person"
>>> Person.count += 1
>>> print(Person.count)
1
>>> print(Person.name)
Person
>>> p1 = Person(); p2 = Person()
>>> print(p1.name, p2.name)
Person Person
>>> Person.name = "雇员"
>>> print(p1.name, p2.name)
雇员 雇员
>>> p1.name = '员工'
>>> print(p1.name, p2.name)
员工 雇员
例9.5(私有属性)
Python类的成员没有访问控制限制,这与其他面向对象语言不同
通常约定以两个下划线开头,但是不以两个下划线结束的属性是私有的(private),其它为公共的(public)
>>> class Person:
__name = 'class Person'
def get_name():
print(Person.__name)
>>> Person.get_name()
class Person
>>> Person.__name
Traceback (most recent call last):
File "" , line 1, in <module>
Person.__name
AttributeError: type object 'Person' has no attribute '__name'
例9.6、9.7、9.8(property装饰器)
- 面向对象编程的封装性原则要求不直接访问类中的数据成员
- 在Python中可以定义私有属性,然后定义相应的访问该私有属性的函数,并使用@property装饰器来装饰这些函数
- 程序可以把函数“当作”属性访问,从而提供更加友好的访问方式
>>> class Person:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
>>> p = Person('zgh666')
>>> print(p.name)
zgh666
尝试了一个想法(如果对象也有一个同名的属性,会怎么样?):
>>> class Person:
name = 'zgh'
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
>>> p = Person('zgh666')
>>> print(p.name)
zgh666
很显然,返回的是装饰器修饰的name函数
@property装饰器默认提供一个只读属性,如果需要,可以使用对应的getter、setter和deleter装饰器实现其他访问器函数
>>> class Person:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
self.__name = value
@name.deleter
def name(self):
del self.__name
>>> p = Person('zgh')
>>> p.name = 'Zhanggguohao'
>>> print(p.name)
Zhanggguohao
property(fget=None, fset=None, fdel=None, doc=None)
>>> class Person:
def __init__(self, name):
self.__name = name
def getname(self):
return self.__name
def setname(self, value):
self.__name = value
def delname(self):
del self.__name
name = property(getname, setname,delname, "I'm the 'name' property.")
>>> p = Person('zgh')
>>> print(p.name)
zgh
>>> p.name = 'zgh666'
>>> print(p.name)
zgh666
例9.9(自定义属性)
在Python中,可以赋予一个对象自定义的属性,即类定义中不存在的属性。对象通过特殊属性
__dict__
存储自定义属性
>>> class Person:
pass
>>> p = Person()
>>> p.name = 'custom name'
>>> p.name
'custom name'
>>> p.__dict__
{'name': 'custom name'}
通过重载
__getattr__
和__setattr__
可以拦截对成员的访问,从而自定义属性的行为
__getattr__()
只有在访问不存在的成员时才会被调用__getattribute__()
拦截所有的(包括不存在)获取操作__setattr__()
设置属性__delattr__()
删除属性
>>> class CustomAttribute(object):
def __init__(self):
pass
def __getattribute__(self, name):
return str.upper(object.__getattribute__(self, name))
def __setattr__(self, name, value):
object.__setattr__(self, name, str.strip(value))
>>> p = CustomAttribute()
>>> p.firstname = ' mary'
>>> print(p.firstname)
MARY
三:方法
对象实例方法的第一个参数一般为self,但是用户调用时不需要也不能给该参数传值
例9.11(静态方法:摄氏温度与华氏温度之间的相互转换)
class TemperatureConverter:
@staticmethod
def c2f(t_c):
return (float(t_c) * 9/5) + 32
@staticmethod
def f2c(t_f):
return ((float(t_f) - 32) * 5/9)
print("1. 从摄氏温度到华氏温度.")
print("2. 从华氏温度到摄氏温度.")
choice = int(input("请选择转换方向:"))
if choice == 1:
t_c = float(input("请输入摄氏温度:"))
t_f = TemperatureConverter.c2f(t_c)
print("华氏温度为:{0:.2f}".format(t_f))
elif choice == 2:
t_f = float(input("请输入华氏温度:"))
t_c = TemperatureConverter.f2c(t_f)
print("摄氏温度为:{0:.2f}".format(t_c))
else:
print("无此选项,只能选择1或2")
输出:
====================== RESTART: D:\zgh\desktop\test.py ======================
1. 从摄氏温度到华氏温度.
2. 从华氏温度到摄氏温度.
请选择转换方向:1
请输入摄氏温度:30
华氏温度为:86.00
>>>
====================== RESTART: D:\zgh\desktop\test.py ======================
1. 从摄氏温度到华氏温度.
2. 从华氏温度到摄氏温度.
请选择转换方向:2
请输入华氏温度:70
摄氏温度为:21.11
>>>
补充一个很有意思的代码:
(包含了很多知识点)
TempStr = input("请输入带有符号的温度值:")
if TempStr[-1] in ['F', 'f']:
C = (eval(TempStr[0:-1]) - 32) / 1.8
print("转化后的温度是{:.2f}C".format(C))
elif TempStr[-1] in ['C', 'c']:
F = 1.8 * eval(TempStr[0:-1]) + 32
print("转化后的温度是{:.2f}F".format(F))
else:
print("输入格式错误")
例9.12(类方法)
类方法的第一个参数为cls,但是调用时用户不需要也不能给该参数传值
>>> class Person:
classname = "zgh"
def __init__(self, name):
self.name = name
#实例方法
def f1(self):
print(self.name)
#静态方法
@staticmethod
def f2():
print("static")
#类方法
@classmethod
def f3(cls):
print(cls.classname)
>>> p = Person("666")
>>> p.f1()
666
>>> Person.f2()
static
>>> p.f2()
static
>>> Person.f3()
zgh
>>> p.f3()
zgh
>>> Person.f1()
Traceback (most recent call last):
File "" , line 1, in <module>
Person.f1()
TypeError: f1() missing 1 required positional argument: 'self'
类名不能访问实例方法
补充:
- 无论是静态方法还是类方法一般通过类名来访问,也可以通过对象实例来调用
- 在静态方法中访问对象实例会导致错误
- 在类方法中访问对象实例属性会导致错误
例9.15(__init__()
方法、__new__()
方法、__del__()
方法)
__init__()
构造函数,用于执行类的实例的初始化工作。在创建完对象后调用,初始化当前对象的实例,无返回值__new__()
是一个类方法,在创建对象时调用,返回当前对象的一个实例,一般无须重载该方法__del__()
析构函数,用于实现销毁类的实例所需的操作,如释放对象占用的非托管资源(打开的文件、网络连接等)
在默认情况下,当对象不再被使用时,__del__()
方法运行。由于Python解释器实现自动垃圾回收,所以无法保证这个方法究竟在什么时候运行
但通过del
语句可以强制销毁一个对象实例,从而保证调用对象实例的__del__()
方法
>>> class Person:
count = 0
def __init__(self, name, age):
self.name = name
self.age = age
Person.count += 1
def __del__(self):
Person.count -= 1
def say_hi(self):
print("hello, i'm ", self.name)
def get_count():
print("count: ",Person.count)
>>> print("count: ", Person.count)
count: 0
>>> p1 = Person('zhangsan', 18)
>>> p1.say_hi()
hello, i'm zhangsan
>>> Person.get_count()
count: 1
>>> p2 = Person('lisi', 28)
>>> p2.say_hi()
hello, i'm lisi
>>> Person.get_count()
count: 2
>>> del p1
>>> Person.get_count()
count: 1
>>> del p2
>>> Person.get_count()
count: 0
例9.16(私有方法)
- 与私有属性类似,Python约定以两个下划线开头,但不以两个下划线结束的方法是私有的
- 不能直接访问私有的
>>> class Book:
def __init__(self, name, author, price):
self.name = name
self.author = author
self.price = price
def __check_name(self):
if self.name == '': return False
else: return True
def get_name(self):
if self.__check_name(): print(self.name, self.author)
else: print("No Value")
>>> b = Book("Python", 'zgh', 666)
>>> b.get_name()
Python zgh
>>> b.__check_name()#直接调用私有方法,非法
Traceback (most recent call last):
File "" , line 1, in <module>
b.__check_name()
AttributeError: 'Book' object has no attribute '__check_name'
例9.17(方法的重载)
Python本身是动态语言,
- 方法的参数没有声明类型(在调用传值时确定参数的类型)
- 参数的数量由可选参数和可变参数来控制
- 故Python对象方法不需要重载,定义一个方法即可实现多种调用,从而实现相当于其他程序设计语言的重载功能
>>> class Person:
def say_hi(self, name=None):
self.name = name
if name ==None: print("hello!")
else: print("hello, i'm ", self.name)
>>> p = Person()
>>> p.say_hi()
hello!
>>> p.say_hi('zgh')
hello, i'm zgh
>>>
注意:在Python类体中定义多个重名的方法虽然不会报错,但只有最后一个方法有效,所以建议不要定义重名的方法
四:继承
- Pyhon支持多重继承,即一个派生类可以继承多个基类
- 如果在类定义中没有指定基类,则默认其基类为
object
- 在声明派生类时,必须在其构造函数中调用基类的构造函数
例9.19(派生类)
>>> class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hi(self):
print("hello, i'm {0}, {1} olds".format(self.name, self.age))
>>> class Student(Person):
def __init__(self, name, age, stu_id):
Person.__init__(self, name, age)
self.stu_id = stu_id
def say_hi(self):
Person.say_hi(self)
print("i'm student, my student_number is ", self.stu_id)
>>> p =Person('zhangsan',18)
>>> p.say_hi()
hello, i'm zhangsan, 18 olds
>>> s = Student('lisi', 5, '17202030118')
>>> s.say_hi()
hello, i'm lisi, 5 olds
i'm student, my student_number is 17202030118
例9.20(查看类的继承关系)
多个类的继承可以形成层次关系,通过类的方法
mro()
或类的属性__mro__
可以输出其继承的层次关系
>>> class A: pass
>>> class B(A): pass
>>> class C(B): pass
>>> class D(A): pass
>>> class E(B,D): pass
>>> A.mro()
[<class '__main__.A'>, <class 'object'>]
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
>>> C.mro()
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
>>>
>>> D.mro()
[<class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
>>>
>>> E.__mro__
(<class '__main__.E'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
例9.21(类成员的继承和重写)
>>> class Dimension:
def __init__(self, x, y):
self.x = x
self.y = y
def area(self):
pass
>>> class Circle(Dimension):
def __init__(self, r):
Dimension.__init__(self, r, 0)
def area(self):
return 3.14 * self.x * self.x
>>> class Rectangle(Dimension):
def __init__(self, w, h):
Dimension.__init__(self, w, h)
def area(self):
return self.x * self.y
>>> d1 = Circle(2.0)
>>> d2 = Rectangle(3.0, 4.0)
>>> print(d1.area(), d2.area())
12.56 12.0
五:对象的特殊方法
- 在Python对象中包含许多以双下划线开始和结束的方法,称之为特殊方法。
- 特殊方法通常在针对对象的某种操作时自动调用
例9.22(重写对象的特殊方法)
特殊方法 | 含义 |
---|---|
__init__() ,__del__() |
创建或销毁对象时调用 |
__setitem__() ,__getitem__() |
按索引赋值、取值 |
__len__() |
对应于内置函数len() |
__repr__(self) |
对应于内置函数repr() |
__str__(self) |
对应于内置函数str() |
__bytes__(self) |
对应于内置函数bytes() |
__format__(self, format_spec) |
对应于内置函数format() |
__bool__(self) |
对应于内置函数bool() |
__hash__(self) |
对应于内置函数hash() |
__dir__(self) |
对应于内置函数dir() |
>>> class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '{0}, {1}'.format(self.name, self.age)
>>> p = Person('zgh', '18')
>>> print(p)
zgh, 18
例9.23(运算符重载)
特殊方法 | 含义 |
---|---|
__lt__() ,__le__() ,__eq__() |
对应于运算符<,<=,== |
__gt__() ,__ge__() ,__ne__() |
对应于运算符>,>=,!= |
__or__() ,__ror__() ;__xor__() ,__rxor__() ;__and__() ,__rand__() |
对应于运算符|,^,& |
__ior__() ,__ixor__() ,__iand__() |
对应于运算符|=,^=,&= |
__lshift__() ,__rlshift__() ;__rshift__() ,__rrshift__() |
对应于运算符<<,>> |
__ilshift__() ,__irlshift__() ;__irshift__() ,__irrshift__() |
对应于运算符<<=,>>= |
__add__() ,__radd__() ;__sub__() ,__rsub__() |
对应于运算符+,- |
__iaddr__() ,__isub__() |
对应于运算符+=,-= |
__mul__() ,__rmul__() ;__truediv__() ,__rtruediv__() |
对应于运算符*,/ |
__mod__() ,__rmod__() ;__floordiv__() ,__rfloordiv__() |
对应于运算符%,// |
__imul__() ,__idiv__() ,__itruediv__() ,__imod__() ,__ifloordiv__() |
对应于运算符*=,/=,%=,//= |
__pos__() ,__neg__() |
正负号 |
__invert__() |
按位翻转 |
__pow__() ,__rpow__() ,__ipow__() |
指数运算 |
看了上这么多特殊方法和运算符的对应,你是否会感到一些奇怪的地方:
r
,某些运算符为啥子有两个,然后其中一个的最前面加了一个r
x.__mul__(y) == x / y
;而x.__rmul__(y) == y / x
>>> class MyList:
def __init__(self, *args):
self.__mylist = []
for arg in args:
self.__mylist.append(arg)
def __add__(self, n):
for i in range(0, len(self.__mylist)):
self.__mylist[i] += n
def __sub__(self, n):
for i in range(0, len(self.__mylist)):
self.__mylist[i] -= n
def __mul__(self, n):
for i in range(0, len(self.__mylist)):
self.__mylist[i] *= n
def __truediv__(self, n):
for i in range(0, len(self.__mylist)):
self.__mylist[i] /= n
def __len__(self):
return (len(self.__mylist))
def __repr__(self):
str1 = ''
for i in range(0, len(self.__mylist)):
str1 += str(self.__mylist[i]) + " "
return str1
>>> m = MyList(1, 2, 3, 4, 5)
>>> m+2
>>> m
3 4 5 6 7
>>> m -1
>>> m
2 3 4 5 6
>>> m*4
>>> m
8 12 16 20 24
>>> m/2
>>> m
4.0 6.0 8.0 10.0 12.0
>>> len(m)
5
例9.24(@functools.total_ordering
装饰器)
实现了
total_ordering
装饰器后,则是需要实现__eq__()
以及__lt__()
、__le__()
、__gt__()
、__ge__()
中的任意一个,那么实现其他比较运算符能简化代码量
import functools
@functools.total_ordering
class Student:
def __init__(self, firstname, lastname):
self.firstname = firstname
self.lastname = lastname
def __eq__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) ==
(other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) <
(other.lastname.lower(), other.firstname.lower()))
if __name__ == '__main__':
s1 = Student('Mary', 'Clinton')
s2 = Student('Mary', 'Clinton')
s3 = Student('Charlie', 'Clinton')
print(s1 == s2)
print(s1 > s3)
print(s1 < s3)
输出:
True
True
False
例9.25(定义了__call__()
方法的对象称为可调用对象)
class GDistance:
def __init__(self, g):
self.g = g
def __call__(self, t):
return (self.g * t ** 2)/2
if __name__ == '__main__':
e_gdist = GDistance(9.8)
for t in range(11):
print(format(e_gdist(t), "0.2f"), end = ' ')
输出:
0.00 4.90 19.60 44.10 78.40 122.50 176.40 240.10 313.60 396.90 490.00
六:对象的引用、浅拷贝和深拷贝
例9.26(对象的引用)
对象的赋值实际上是对象的引用,在创建一个对象并把它赋值给一个变量时,该变量是指向该对象的引用,其id()返回值保持一致
>>> acc10 = ['zgh', ['zgh666', 666]]
>>> acc11 = acc10
>>> id(acc10) == id(acc11)
True
例9.27(对象的浅拷贝)
对象的赋值引用同一个对象(即:不复制对象)
如果要复制对象,可以使用下列方法之一:
- 切片操作:例如acc11[:]
- 对象实例化:例如list(acc11)
- copy模块的copy()函数:例如copy.copy(acc11)
>>> import copy
>>> acc1 = ['Charlie', ['credit', 0.0]]
>>> acc2 = acc1[:]
>>> acc3 = list(acc1)
>>> acc4 = copy.copy(acc1)
>>> id(acc1), id(acc2), id(acc3), id(acc4)
(2387738921800, 2387738921544, 2387735787656, 2387738922888)
Python复制一般是浅拷贝,即复制对象时,对象内包含的子对象并不复制,而是引用同一个子对象
>>> acc2[0] = 'zgh666'
>>> acc2[1][1] = 100.0
>>> acc1
['Charlie', ['credit', 100.0]]
>>> acc2
['zgh666', ['credit', 100.0]]
>>> id(acc1[1]) == id(acc2[1])
True
例9.28(对象的深拷贝)
使用copy模块的deepcopy()函数
>>> import copy
>>> acc1 = ['Charlie', ['credit', 0.0]]
>>> acc5 = copy.deepcopy(acc1)
>>> acc5[0] = 'zgh666'
>>> acc5[1][1] = 666
>>> acc1
['Charlie', ['credit', 100.0]]
>>> acc5
['zgh666', ['credit', 666]]
>>> id(acc1) == id(acc5)
False
>>> id(acc1[1]) == id(acc5[1])
False
七:可迭代对象:迭代器和生成器
相对于序列,可迭代对象仅在迭代时产生数据,故可以节省内存空间
__iter__()
的对象是可迭代对象>>> import collections.abc
>>> isinstance((1, 2, 3), collections.abc.Iterable)
True
>>> isinstance('Python33', collections.abc.Iterable)
True
>>> isinstance(123, collections.abc.Iterable)
False
__next__()
的对象是迭代器>>> [i**2 for i in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> import collections.abc
>>> i1 = (i**2 for i in range(10))
>>> isinstance(i1, collections.abc.Iterator)
True
__iter__()
、__next__()
,二者合称为迭代器协议__iter__()
用于返回对象本身,以方便for语句进行迭代__next__()
用于返回下一元素iter(iterable)
可以返回可迭代对象iterable的迭代器next()
调用迭代器__next__()
方法依次返回下一个项目值,如果没有新项目,则将导致StopIteration>>> t = ('zgh', '666')
>>> i = iter(t)
>>> next(i)
'zgh'
>>> next(i)
'666'
>>> next(i)
Traceback (most recent call last):
File "" , line 1, in <module>
next(i)
StopIteration
>>> t = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> fetch = iter(t)
>>> while True:
try: i = next(fetch)
except StopIteration: break
print(i, end = ' ')
0 1 2 3 4 5 6 7 8 9
声明一个类,定义
__iter__()
、__next__()
方法。创建该类的对象既是可迭代对象,也是迭代器
>>> class Fib:
def __init__(self):
self.a, self.b = 0, 1
def __next__(self):
self.a, self.b = self.b, self.a+self.b
return self.a
def __iter__(self):
return self
>>> fibs = Fib()
>>> for i in fibs:
if i < 1000: print(i, end =', ')
else: break
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987,
>>> def triples(n):
for i in range(n):
yield i*3
>>> f = triples(10)
>>> f
<generator object triples at 0x0000022BF0563DC8>
>>> i = iter(f)
>>> next(i)
0
>>> next(i)
3
>>> for t in f: print(t, end = ', ')
6, 9, 12, 15, 18, 21, 24, 27,
>>> def fib():
a,b = 0,1
while True:
a,b = b,a+b
yield a
>>> if __name__ == '__main__':
fibs = fib()
for f in fibs:
if f < 1000: print(f, end = ' ')
else: break
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> import math
>>> def is_prime(n):
if n < 2: return False
if n == 2: return True
if n % 2 == 0: return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n+1, 2):
if n % i == 0: return False
return True
>>> def primes(m, n):
for i in range(m, n+1):
if is_prime(i):
yield i
>>> if __name__ == '__main__':
primes1 = primes(50_0000_0000, 50_0000_0090)
for p in primes1:
print(p, end = ' ')
5000000029 5000000039 5000000059 5000000063
只有长度有限的序列或者实现了
__reversed__()
方法的可迭代对象才可以使用内置函数reversed()
>>> reversed([1, 2, 3, 4, 5])
<list_reverseiterator object at 0x0000022BF04FE608>
>>> for i in reversed([1, 2, 3, 4, 5]): print(i, end = ' ')
5 4 3 2 1
__reversed__()
方法的可迭代对象才可以使用内置函数reversed()
>>> class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1
def __reversed__(self):
n = 1
while n <= self.start:
yield n
n += 1
>>> if __name__ == '__main__':
for i in Countdown(10): print(i, end = ' ')
for i in reversed(Countdown(10)): print(i, end = ' ')
10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10
()
代替[]
>>> (i **2 for i in range(10))
<generator object <genexpr> at 0x0000022BF0563F48>
>>> for j in (i **2 for i in range(10)):
print(j, end = ' ')
0 1 4 9 16 25 36 49 64 81
>>> for j in (i **2 for i in range(10) if i %3 == 0):
print(j, end = ' ')
0 9 36 81
map(function, iterable, ...)
函数itertools.starmap()
迭代器>>> import itertools
>>> list(itertools.starmap(pow, [(2,5), (3,2), (10,3)]))
[32, 9, 1000]
filter(function, iterable)
函数,若结果为True,则返回该元素。如果function为None,则返回元素为True的元素itertools.filterfalse(predicate, iterable)
则反之>>> filter
<class 'filter'>
>>> list(filter(lambda x : x > 0, (-1, 2, -3, 0, 5)))
[2, 5]
>>> list(filter(None, (1, 2, 3, 0, 5)))
[1, 2, 3, 5]
>>>
>>> import itertools
>>> list(itertools.filterfalse(lambda x : x%2, range(10)))
[0, 2, 4, 6, 8]
zip(*iterables)
用于拼接多个可迭代对象的元素,返回新的可迭代对象。如果各序列的长度不一致,则截取至最小序列长度itertools.zip_longest(*iterables, fillvalue = None)
迭代器>>> zip
<class 'zip'>
>>> zip((1,2,3), 'abc', range(3))
<zip object at 0x000001B3CDD758C8>
>>> list(zip((1,2,3), 'abc', range(3)))
[(1, 'a', 0), (2, 'b', 1), (3, 'c', 2)]
>>> list(zip('zgh', range(6,10)))
[('z', 6), ('g', 7), ('h', 8)]
>>>
>>>
>>> import itertools
>>> list(itertools.zip_longest('zgh', range(6,10), fillvalue = '-'))
[('z', 6), ('g', 7), ('h', 8), ('-', 9)]
>>> list(itertools.zip_longest('zgh', range(6,10)))
[('z', 6), ('g', 7), ('h', 8), (None, 9)]
>>> enumerate
<class 'enumerate'>
>>> list(enumerate('zgh666', start = 666))
[(666, 'z'), (667, 'g'), (668, 'h'), (669, '6'), (670, '6'), (671, '6')]
count(start = 0, step = 1)
cycle(iterable)
repeat(object[, times])
>>> from itertools import *
>>> list(zip(count(1), 'zgh666'))
[(1, 'z'), (2, 'g'), (3, 'h'), (4, '6'), (5, '6'), (6, '6')]
>>> list(zip(range(10), cycle('zgh')))
[(0, 'z'), (1, 'g'), (2, 'h'), (3, 'z'), (4, 'g'), (5, 'h'), (6, 'z'), (7, 'g'), (8, 'h'), (9, 'z')]
>>> list(repeat('zgh', 6))
['zgh', 'zgh', 'zgh', 'zgh', 'zgh', 'zgh']
accumulate(iterable[, func])
>>> import itertools
>>> list(itertools.accumulate(range(1,11)))
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
>>> import operator
>>> list(itertools.accumulate(range(1,11), operator.mul))
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
chain(*iterables)
chain.from_iterable(iterable)
也可以用于连接多个序列>>> import itertools
>>> list(itertools.chain('zgh',(6,6,6),range(5)))
['z', 'g', 'h', 6, 6, 6, 0, 1, 2, 3, 4]
>>>
>>> list(itertools.chain.from_iterable(['zgh', '666']))
['z', 'g', 'h', '6', '6', '6']
compress(data, selectors)
>>> import itertools
>>> list(itertools.compress('abcdef', [1,0,1,0,1,1]))
['a', 'c', 'e', 'f']
dropwhile(predicate, iterable)
takewhile(predicate, iterable)
>>> import itertools
>>> list(itertools.dropwhile(lambda x : x < 5, [1, 4, 6, 4, 1]))
[6, 4, 1]
>>> list(itertools.takewhile(lambda x : x < 5, [1, 4, 6, 4, 1]))
[1, 4]
islice(iterable, stop)
islice(iterable, start, stop[, step])
>>> import itertools
>>> list(itertools.islice('ABCDEF', 2))
['A', 'B']
>>> list(itertools.islice('ABCDEF', 2, 4))
['C', 'D']
>>> list(itertools.islice('ABCDEF', 2, None))
['C', 'D', 'E', 'F']
>>> list(itertools.islice('ABCDEF', 0, None, 2))
['A', 'C', 'E']
groupby(iterable, key = None)
>>> import itertools
>>> data = [1, -2, 0, 0, -1, 2, 1, -1, 2, 0, 0]
>>> data1 = sorted(data, key = abs)
>>> for k, g in itertools.groupby(data, key = abs):
print(k, list(g))
1 [1]
2 [-2]
0 [0, 0]
1 [-1]
2 [2]
1 [1, -1]
2 [2]
0 [0, 0]
>>> for k, g in itertools.groupby(data1, key = abs):
print(k, list(g))
0 [0, 0, 0, 0]
1 [1, -1, 1, -1]
2 [-2, 2, 2]
tee(iterable, n = 2)
>>> import itertools
>>> for i in itertools.tee(range(10), 3): print(list(i))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
combinations(iterable, r)
combinations_with_replacement(iterable, r)
>>> import itertools
>>> list(itertools.combinations([1, 2, 3], 2))
[(1, 2), (1, 3), (2, 3)]
>>> list(itertools.combinations([1, 2, 3, 4], 2))
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
>>> list(itertools.combinations([1, 2, 3, 4], 3))
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
>>>
>>>
list(itertools.combinations_with_replacement([1, 2, 3], 2))
[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
permutations(iterable, r = None)
>>> import itertools
>>> list(itertools.permutations([1, 2, 3], 2))
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
>>> list(itertools.permutations([1, 2, 3]))
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
product(*iterables, repeat = 1)
>>> import itertools
>>> list(itertools.product([1, 2], 'abc'))
[(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c')]
>>> list(itertools.product([1, 2], repeat = 3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]
八:自定义类应用举例
用户可以通过自定义类创建和使用新的数据结构
例9.52 实现RGB颜色模型的Color类
class Color:
def __init__(self, r = 0, g = 0, b = 0):
self.__r = r
self.__g = g
self.__b = b
@property
def r(self):
return self.__r
@property
def g(self):
return self.__g
@property
def b(self):
return self.__b
def luminance(self):
#计算并返回颜色的亮度
return self.__r * .299 + .587 * self.__g + .114 * self.__b
def toGray(self):
#转换为灰度颜色
y = int(round(self.luminance()))
return Color(y, y, y)
def isCompatible(self, c):
#比较前景色和背景色是否匹配
return abs(self.luminance() - c.luminance()) >= 128.0
def __str__(self):
#重载方法,输出:(r, g, b)
return '({}, {}, {})'.format(self.__r, self.__g, self.__b)
#常用颜色
WHITE = Color(255, 255, 255)
BLACK = Color(0, 0, 0)
RED = Color(255, 0, 0)
GREEN = Color(0, 255, 0)
BLUE = Color(0, 0, 255)
CYAN = Color(0, 255, 255)
MAGENTA = Color(255, 0, 255)
YELLOW = Color(255, 255, 0)
#测试代码
if __name__ == '__main__':
c = Color(255, 200, 0)
print('颜色字符串:{0}'.format(c))
print('颜色分量:r = {0}, g = {1}, b = {1}'.format(c.r, c.g, c.b))
print('颜色亮度:{0}'.format(c.luminance()))
print('转换为灰度颜色:{0}'.format(c.toGray()))
print('{0} 和 {1} 是否匹配:{2}'.format(c, RED, c.isCompatible(RED)))
例9.53 实现直方图类Histogram
import random
import math
class Stat:
def __init__(self, n):
self.__data = []
for i in range(n):
self.__data.append(0)
def addDataPoint(self, i):
"""增加数据点"""
self.__data[i] += 1
def count(self):
"""计算数据点个数之和(统计数据点个数)"""
return sum(self.__data)
def mean(self):
"""平均值"""
return sum(self.__data)/len(self.__data)
def max(self):
return max(self.__data)
def min(self):
return min(self.__data)
def draw(self):
"""绘制简易直方图"""
for i in self.__data:
print(' # ' * i)
if __name__ == '__main__':
st = Stat(10)
for i in range(100):
score = random.randrange(0, 10)
st.addDataPoint(math.floor(score))
print('数据点个数:{}'.format(st.count()))
print('数据点个数的平均值:{}'.format(st.mean()))
print('数据点个数的最大值:{}'.format(st.max()))
print('数据点个数的最小值:{}'.format(st.min()))
st.draw()
输出:
数据点个数:100
数据点个数的平均值:10.0
数据点个数的最大值:14
数据点个数的最小值:7
# # # # # # # #
# # # # # # # # # #
# # # # # # # # #
# # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # #
# # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # # # #
# # # # # # #
2
>>> x = '123'
>>> print(isinstance(x, int))
False
3
在声明派生类时,必须在其构造函数中调用基类的构造函数
>>> class Parent:
def __init__(self, param):
self.v1 = param
>>> class Child(Parent):
def __init__(self, param):
Parent.__init__(self, param)
self.v2 = param
>>> obj = Child(100)
>>> print("%d %d" % (obj.v1, obj.v2))
100 100
4
注意区分实例对象属性和局部变量
>>> class Account:
def __init__(self, id):
self.id = id
id = 888
>>> acc = Account(100)
>>> print(acc.id)
100
5
>>> #5
>>> class Account:
def __init__(self, id, balance):
self.id = id
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
>>> acc1 = Account('1234', 100)
>>> acc1.deposit(500)
>>> acc1.withdraw(200)
>>> print(acc1.balance)
400
6
getattr(object, name[, default])
setattr(object, name, value)
>>> class A:
def __init__(self, a, b, c):
self.x = a+b+c
>>> a = A(6, 2, 3)
>>> b = getattr(a, 'x')
>>> setattr(a, 'x', b+1)
>>> print(a.x)
12
7
浅拷贝,复制对象时对象中包含的子对象并不复制,而是引用同一个子对象
>>> import copy
>>> d1 = {'a' : [1, 2], 'b' : 2}
>>> d2 = copy.copy(d1)
>>> d1['a'][0] = 6
>>> sum = d1['a'][0] + d2['a'][0]
>>> print(sum)
12
8
深拷贝,可以递归复制对象中包含的子对象
>>> from copy import *
>>> d1 = {'a' : [1, 2], 'b' : 2}
>>> d2 = deepcopy(d1)
>>> d1['a'][0] = 6
>>> sum = d1['a'][0] + d2['a'][0]
>>> print(sum)
7
9
浅拷贝,复制对象时对象中包含的子对象并不复制,而是引用同一个子对象
>>> from copy import *
>>> list1 = [1, 2, 3]
>>> list2 = [3, 4, 5]
>>> dict1 = {"1" : list1, '2' : list2}
>>> dict2 = dict1.copy()
>>> dict1['1'][0] = 15
>>> print(dict1['1'][0] + dict2['1'][0])
30
10
深拷贝,可以递归复制对象中包含的子对象
>>> from copy import *
>>> list1 = [1, 2, 3]
>>> list2 = [3, 4, 5]
>>> dict1 = {"1" : list1, '2' : list2}
>>> dict2 = deepcopy(dict1)
>>> dict1['1'][0] = 15
>>> print(dict1['1'][0] + dict2['1'][0])
16
11
对象通过特殊属性__dict__
存储属性,包括自定义属性
>>> class Person:
def __init__(self, id):
self.id = id
>>> mary = Person(123)
>>> mary.__dict__['age'] = 18
>>> mary.__dict__['gender'] = 'female'
>>> print(mary.age + len(mary.__dict__))
21
>>> mary.__dict__
{'id': 123, 'age': 18, 'gender': 'female'}
2. 编写程序,创建类MyMath,计算圆的周长和面积以及球的表面积和体积,并编写测试代码,结果均保留两位小数
import math
class MyMath:
def __init__(self, r):
self.r = r
def perimeter_round(self):
return 2 * math.pi * self.r
def area_round(self):
return math.pi * self.r * self.r
def area_ball(self):
return 4 * math.pi * self.r ** 2
def volume_ball(self):
return 4 / 3 * math.pi *self.r ** 3
if __name__ == '__main__':
n = float(input("请输入半径:"))
m = MyMath(n)
print("圆的周长 = {0:.2f}\n圆的面积 = {1:.2f}\n球的表面积 = {2:.2f}\n球的体积 = {3:.2f}".\
format(m.perimeter_round(), m.area_round(), m.area_ball(), m.volume_ball()))
输出:
请输入半径:5
圆的周长 = 31.42
圆的面积 = 78.54
球的表面积 = 62.83
球的体积 = 523.60
3. 编写程序,创建类Temperature,其包含成员变量degree(表示温度)以及实例方法ToFahrenheit(将摄氏温度转换为华氏温度)和ToCelsius(将华氏温度转换为摄氏温度),并编写测试代码
class Temperature:
def __init__(self, degree):
self.degree = degree
def toFahrenheit(self):
return self.degree*9/5 + 32
def toCelsius(self):
return (self.degree -32) * 5/9
if __name__ == '__main__':
n1 = float(input("请输入摄氏温度:"))
t1 = Temperature(n1)
print("摄氏温度 = {0:.2f}, 华氏温度 = {1:.2f}".format(n1, t1.toFahrenheit()))
n2 = float(input("请输入华氏温度:"))
t2 = Temperature(n2)
print("摄氏温度 = {0:.2f}, 华氏温度 = {1:.2f}".format(t2.toCelsius(), n2))
输出:
请输入摄氏温度:30
摄氏温度 = 30.00, 华氏温度 = 86.00
请输入华氏温度:70
摄氏温度 = 21.11, 华氏温度 = 70.00