- 字符转整数
num = ord('a')
- 整数转字符
ch = chr(65)
不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
可变对象,该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变。
Python中,数值类型(int和float)、字符串str、元组tuple都是不可变类型。而列表list、字典dict、集合set是可变类型。
dict key是不可变对象
- 和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢; 需要占用大量的内存,内存浪费多;
- 而list相反: 查找和插入的时间随着元素的增加而增加; 占用空间小,浪费内存很少;
- 定义函数时,需要确定函数名和参数个数;
- 如果有必要,可以先对参数的数据类型做检查;
- 函数体内部可以用return随时返回函数结果;
- 函数执行完毕也没有return语句时,自动return None。
- 函数可以同时返回多个值,但其实就是一个tuple。
- 使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
- 针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
- Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
len只接受字符串输入
list tuple string
[from:to:interval]def findMinAndMax(L):
max1 = min1 = 0
if isinstance(L, Iterable) is False: # whether or not iterable
print("error: do not iterable")
for value in L:
if value > max1:
max1 = value
continue
elif value < min1:
min1 = value
continue
else:
continue
return min1, max1L7 = ['Hello', 'World', 18, 'Apple', None]
L8 = [ key for key in L7 if isinstance(key, str)]
print(L8)# 列表生成式
L9 = [x * x for x in range(1,8)]
print(L9)
# 生成器
L10 = (x * x for x in range(1,8))
# print(L10)
for g in L10:
print(g)
包含yield的函数
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
-
一类是集合数据类型,如list、tuple、dict、set、str等;
-
一类是generator,包括生成器和带yield的generator function。
-
Iterable 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。 可以使用isinstance()判断一个对象是否是Iterable对象。 Iterable对象存放在内存中,数量是有限的
-
Iterator 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
- 凡是可作用于for循环的对象都是Iterable类型;
- 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
- 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
集合也有一个与列表一样的 pop 方法。 从集合 pop 一个元素时,一个随机元素被删除(记住,集合不同于列表,是无序的,所以没有 "最后一个元素"。
Python的for循环本质上就是通过不断调用next()函数实现的。
it = iter([1, 2, 3, 4, 5])
while True:
try:
x = next(it)
print(x)
except StopIteration as e:
if e.value is None:
continue
print(e.value)- 函数本身也可以赋值给变量,即:变量可以指向函数。
- 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
# char to int
def char2num(s):
digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
return digits[s]
#print(char2num('0'))
# num1num2 = num1*10 + num2
def str2int(num1, num2):
return num1 * 10 + num2
def str2int2(string):
return reduce(str2int, map(char2num, string))
print(str2int2('123456'))# string to float
def str2float(ff):
return reduce(str2int, map(char2num, ff.split('.')[0])) + reduce(str2int, map(char2num, ff.split('.')[1])) / 10 ** len(ff.split('.')[1])
print('str2float(\'123.456\') =', str2float('123.456'))
if abs(str2float('123.456') - 123.456) < 0.00001:
print('测试成功!')
else:
print('测试失败!')def not_empty(s):
return s and s.strip()
L13 = list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
print(L13)L14 = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return str.lower(t[0])
def by_score(t):
return t[-1]
L15 = sorted(L14, key=by_name)
L16 = sorted(L14, key=by_score, reverse=True)def lazy_sum(*args):
def sum():
all = 0
for value in args:
all = all + value
return all
return sum
L17 = (1, 2, 3, 3, 4, 5)
f4 = lazy_sum(1, 2, 3, 3, 4, 5)
print(f4())- 我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
- 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
- 如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变。本质是内部函数引用外部变量的值。
def count2():
fs = []
def f(j): # bind current loop variable
def g():
return j*j
return g
for i in range(1, 4):
fs.append(f(i))
return fs
f1, f2, f3 = count2()
print(f1())
print(f2())
print(f3())def createCounter():
num = 0
def counter():
nonlocal num # reference outer variable
num = num + 1
return num
return counter
# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
print('测试通过!')
else:
print('测试失败!')匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
def is_odd(n):
return n % 2 == 1
L19 = list(filter(is_odd, range(1, 20)))
is_odd2 = lambda x : x%2 == 1
L20 = list(filter(lambda x : x%2 == 1, range(1,20)))
L21 = list(filter(is_odd2, range(1,20))) # 匿名函数
print(L20)
print(L21)
def build1(x, y):
return lambda: x * x + y * y # 返回匿名函数
L22 = build1(1,2)
print(L22)现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
print("---------------------%s------------------------\n" %("decorator"))
# print(build1.__name__)
# two layers of nested
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
print(now())
print("func name: %s" % now.__name__)
print("---------------------%s------------------------\n" %("decorator"))
# three layers of nested
def log2(text):
def decorator(func):
def wrapper(*args, **kw):
print('call: %s %s():' %(text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log2('execute')
def now2():
print('2015-3-25')
print(now2())
print(now2.__name__)---------------------decorator------------------------
call now():
2015-3-25
None
func name: wrapper
---------------------decorator------------------------
call: execute now2():
2015-3-25
None
wrapperdef metric(fn):
def wrapper(*args, **kw):
start = time.time()
print('call start: %s %s():' % (fn.__name__, start))
num = fn(*args, **kw)
end = time.time()
print('call end: %s %s():' % (fn.__name__, end))
print('%s executed in %s ms' % (fn.__name__, end - start))
return num
return wrapper
# 测试
@metric
def fast(x, y):
time.sleep(0.0012)
return x + y;
@metric
def slow(x, y, z):
time.sleep(0.1234)
return x * y * z;
f = fast(11, 22)
s = slow(11, 22, 33)
print(f)
print(s)
if f != 33:
print('测试失败!')
elif s != 7986:
print('测试失败!')简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
int2 = functools.partial(int, base=2)
print(int2('1000000'))
int10 = functools.partial(int, base=8) # 默认输入八进制
print(int10('12'))特殊方法“init”前后分别有两个下划线!!!
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def get_grade(self):
if self.__score >= 90:
return 'A'
elif self.__score >= 60:
return 'B'
else:
return 'C'
def print_student(self):
print("name%s, score=%s" %(self.__name, self.__score))
def get_score(self):
return self.__score
def get_name(self):
return self.__name
def set_score(self, score):
if 0<= score <= 100 :
self.__score = score
else:
raise ValueError("score should range 0-100")
def set_name(self, name):
self.__name = name
student = Student('Oppo', 23)
student.print_student()
score_level = student.get_grade()
print(score_level)
# debug throw exception
# student.set_score(-1)class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
animal = Animal()
animal.run()
animal = Dog()
animal.run()
animal = Cat()
animal.run()- isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上.
- 能用type()判断的基本类型也可以用isinstance()判断.
class MyObject(object):
def __init__(self):
self.x = 9
def power(self):
return self.x * self.x
myobject = MyObject()
print(hasattr(myobject, 'x'))
setattr(myobject, 'x', 10)
setattr(myobject, 'y', 13)
print(getattr(myobject, 'y', -1))
if hasattr(myobject, 'power'):
power = getattr(myobject, 'power', -1)
print(power())由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
class Student(object):
count = 0 # static varible
def __init__(self, name):
self.name = name # instance varible
Student.count += 1- 使用__slots__限制实例的属性
- 用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
class Teacher(object):
__slots__ = ('name', 'age', 'score')
t = Teacher()
t.name = "xiaomi"
print(t.name)
# dynamic bind function for instance
def set_age(self, age):
self.age = age
# after init __slots__ , don't allow bind set_age
# t.set_age = MethodType(set_age, t)
#
# t.set_age(23)
# print(t.age)
#
t2 = Teacher() # unbind on other instance
# t2.set_age(12)
# print(t2.age)
def set_score(self, score):
self.score = score
# bind function on object
Teacher.set_score = set_score
t2.set_score(89)
print(t2.score)
class GraduateTeacher(Teacher):
pass
# __slots__ is noeffective to child class
g = GraduateTeacher()
g.gender = 'M'
print(g.gender)- 既能检查参数,又可以用类似属性这样简单的方式来访问类的变量
class Screen(object):
def __init__(self):
pass
@property
def width(self):
return self._width
@width.setter
def width(self, value):
self._width = value
@property
def height(self):
return self._height
@width.setter
def height(self, value):
self._height= value
@property
def resolution(self):
return self._width * self._height
# 测试:
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!')MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。
class Alpaca(object):
def __init__(self, name):
self.name = name
def __str__(self):
return "Alpaca name:%s " % self.name
def __repr__(self):
return "Alpaca repr name:%s " % self.name
alpaca = Alpaca("mie")from enum import Enum, unique
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, member.value)
@unique
class Gender(Enum):
Male = 0
Female = 1
class Student(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
# 测试:
bart = Student('Bart', Gender.Male)
if bart.gender == Gender.Male:
print('测试通过!')
else:
print('测试失败!')
print(Gender.Male.value)
print(Gender(0).value)要创建一个class对象,type()函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
- class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
print("---------------------%s------------------------\n" % ("metaclass"))
from plat import Plat
pl = Plat()
pl.plat()
print(type(Plat)) # class type is Type
print(type(pl)) # instance type is Class Type
print("---------------------%s------------------------\n" % ("type create new class"))
def fn(self, name="pine"):
print("plat: %s" % name)
Plat2 = type("Plat", (object,), dict(pp=fn))
pl2 = Plat2()
pl2.pp()try:
10/0
except ZeroDivisionError as e:
print(e)
finally:
print("done")协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
看起来A、B的执行有点像多线程,但协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
def consumer():
num = 0
r = ''
while True:
num = num + 1
print("----> %2d" % num)
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):
r2 = c.send(None)
if r2 == '':
print('c send None return null')
else:
print('c send None return: %s' % r2)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
----> 1
c send None return null
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
----> 2
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
----> 3
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
----> 4
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
----> 5
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
----> 6
[PRODUCER] Consumer return: 200 OK
import matplotlib.pyplot as plt
# x_values = [1, 2, 3, 4, 5]
# y_values = [1, 4, 9, 16, 25]
x_values = list(range(1,1001))
y_values = [x_ * x_ for x_ in x_values]
# 绘制指定的x,y
# plt.scatter(2, 4, s=200)
# debug
# ll1 = [x_ * x_ for x_ in x_values]
# 绘制一系列的x,y
# edgecolors='none' 删除数据的的轮廓
# c=y_values, cmap=plt.cm.Greens 根据y值设置颜色
plt.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Greens, edgecolors='none', s=10)
# 设置图表标题,并给坐标轴加上标签
plt.title("Square Numbers", fontsize=24)
plt.xlabel("value", fontsize=14)
plt.ylabel("square of value", fontsize=14)
plt.tick_params(axis='both', which='major', labelsize=10)
# 设置每个坐标轴的取值范围
plt.axis([0, 1000, 0, 1100000])
# plt.show()
plt.savefig('squares_plot.png', bbox_inches='tight')import matplotlib.pyplot as plt
from random_walk import RandomWalk
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
plt.figure(dpi=128, figsize=(10, 6))
point_numbers = list(range(rw.num_points))
'''
# 随机点的轨迹
plt.plot(rw.x_values, rw.y_values, linewidth=1)
'''
# 随机点的分布
plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Greens, edgecolors='none', s=10)
# 突出起点和终点
plt.scatter(rw.x_values[0], rw.y_values[0], c='green', edgecolors='none', s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100)
# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False)
plt.axes().get_yaxis().set_visible(False)
# plt.show()
plt.savefig('RandomWalk.svg', bbox_inches='tight')
# keep_running = input('\ny or n:')
# if keep_running == 'n':
# print('good bye')
# break
breakfrom die import Die
import pygal
die = Die(6)
die2 = Die(6)
die3 = Die(6)
# results = []
# for roll_num in range(50000):
# result = die.roll() + die2.roll()
# results.append(result)
# print(results)
results = [die.roll() * die2.roll() * die3.roll() for roll_num in range(10000)]
# frquencies = []
max_num = die.num_sides * die2.num_sides * die3.num_sides
# for value in range(2, max_num + 1):
# frquency = results.count(value)
# frquencies.append(frquency)
frquencies = [ results.count(value) for value in range(1, max_num + 1)]
hist = pygal.Bar()
hist.title = "Result of rolling one D6 1000 times"
hist.x_labels = [ str(x) for x in range(1, max_num + 1)]
hist.x_title = 'Result'
hist.y_title = "Frequency of Result"
hist.add('D6 + D6', frquencies)
hist.render_to_file('die_visual2.svg')
# print(frquencies)