1.语句
1.1 print语句
print('age',42)
print('age',42,sep = "-")#自定义分割符
print('age',42,end = '!')#自定义结束符
1.2 import语句
import math可以调用math.sqrt(),from math import sqrt可以直接用sqrt()
1.3 赋值语句
- 序列解包:"="的左右两边互相对应时赋值,'*'可以接受多余的值
name = 'a b c d'
first, *middle, last = name.split()#middle是['b', 'c']
- 链式赋值
a = b = 3
1.4 条件语句
if else,elif = else if,注意==是判断引用变量的值是否相等,is是判断两个变量的引用对象是否相同
1.5 断言
用assert充当判断
assert 0 < age < 100, 'the age must be realistic'
1.6 循环语句
- for(range), while, break, continue等关键字。
while可以和else直接配合,没执行break时会执行else
from math import sqrt
for n in range(99, 81, -1):
root = sqrt(n)
if root == int(root):
print(n)
break
else:
print("Didn't find it!")
- zip(list1, list2) 得到可迭代对象,用list()转化后可以解包,长度不同时按照最小序列长度
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
list(zip(names,ages))#[('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')
- enumerate方便迭代时获取索引
1.7 简单推导语句
print([x*x for x in range(10) if x % 3 == 0])
print([(x, y) for x in range(10) for y in range(3)])#2重循环
1.8 pass语句
1.9 del语句
注意:python中'='符号只是对象的引用,当r=s表示指向了同一个空间,如果这个空间不删掉,就算r=None,s=None也是没用的;del可以删除名称r,s,但也没删除空间
s = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
r = s
s = None#现在令s指向另一块存储空间,r指向的空间没变,所以也有值!!!'='并不是改变的原空间,即r和s都是对象的引用而已
print(r)
r = None#但如果把r也转移,那这个字典就漂浮在计算机内存中,Python解释器直接将其删除,另一种方法是用del
del r#删除名称r,并不是删除了空间,若还有指向空间的,则也有值
1.10 exec语句
- 将字符串作为代码执行
exec("print('hello world')")
- 用来避免命名空间的错误 只有一个参数时会出现问题
from math import sqrt
scope = {}
exec('sqrt = 1', scope)
print(sqrt(4))#正常执行
print(scope['sqrt'])#scope最为字典从中取值
print(scope)#key有两个:sqrt和__builtins__,__builtins__是包含所有内置函数和值的字典
1.11 eval语句
计算用字符串表示的Python表达式的值,并返回结果(exec什么都不返回,因为它本身是条语句)
(神奇,可以自动计算)
2.函数
2.1 __doc__属性
2.2局部作用域
- 不可变类型不会被改变
def try_to_change(n):
n = 'Mr.Gumby'
name = 'Mrs.Gumby'
try_to_change(name)
print(name)#name不会变,因为n=name后,n=xx,则n的指向变了
#或者说,传入的是不可变类型,于是新建一个a,这个a是2的引用(并且是局部的),与传入的a没关系
def func(a):
a = 2
return a
a = 1
print(func(a))#2
print(a)#1
- 可变类型会被改变
def change(n):
n[0] = 'Mr. Gumby'
names = ['Mrs. Entity', 'Mrs. Thing']
change(names)
print(names)#names是变了的,很简单,因为指向的列表,列表内容变了,并不是让他指向别处了
#但是如果传入切片就不用变
change(names[:])
print(names)#不会变,因为切片是副本
2.3 参数
- 关键字参数
def hello_4(name, greeting='Hello', punctuation='!'):
print('{}, {}{}'.format(greeting, name, punctuation))
- 收集参数时用:*用在定义的地方
- *接收元组,** 接收字典
def in_the_middle(x,*y,z):
print(x,z,y)
in_the_middle(1,2,3,4,5,z=6)#如果不在最后,最后一个必须指定=
def demo(num, *args,**kwargs):
print(num)
print(args)#(2, 3)
print(kwargs)
demo(1,2,3,name = "ab",age = 18)#{'name': 'ab', 'age': 18}
def demo2(*args,**kwargs):
print(args)
print(kwargs)
p1 = (1,2,3)
p2 = {"name" : "ab","age" : 18}
demo2(p1, p2)#args会把p1p2当作2个参数,放在一个元组里,实际需要拆包,把p1p2的值都分出来,然后再让定义中的args kwargs接收
'''
((1, 2, 3), {'name': 'ab', 'age': 18})
{}
'''
demo2(*p1, **p2)
- 分配参数时用,*用到调用函数的地方
def add(x, y):
return x + y
params = (1, 2)#参数是元组,用*
add(*params)#自动拆开
def hello_3(greeting='Hello', name='world'):
print('{}, {}!'.format(greeting, name))
params = {'name': 'Sir Robin', 'greeting': 'Well met'}#参数是字典,用**,相当于多指定了名字而已
hello_3(**params)#自动拆开
2.4 变量
- 局部变量与全局变量 局部变量:函数内,全局变量:在函数内如果有局部变量和他同名可能出现问题,常用globals来访问,globals[key]
def combine(parameter):
print(parameter + globals()['parameter'])
parameter = 'berry'
combine('Shrub')
- 重新关联
x = 1
def change_global():
global x
x=x+1
change_global()
print(x)
2.5 新函数
- map(func, seq[, seq, ...]):对序列中的所有元素执行函数
- filter(func, seq):返回一个列表,其中包含对其执行函数时结果为真的所有元素
- reduce(func, seq[, initial]):等价于 func(func(func(seq[0], seq[1]), seq[2]), ...)
- sum(seq):返回 seq 中所有元素的和
- apply(func[, args[, kwargs]]):调用函数(还提供要传递给函数的参数)
3.对象
3.1 多态
通俗来说是只关心对象的实例方法是否同名,不关心对象所属的类型
class Duck(object): # 鸭子类
def fly(self):
print("鸭子沿着地面飞起来了")
class Swan(object): # 天鹅类
def fly(self):
print("天鹅在空中翱翔")
class Plane(object): # 飞机类
def fly(self):
print("飞机隆隆地起飞了")
def fly(obj): # 实现飞的功能函数
obj.fly()
duck = Duck()
fly(duck)
swan = Swan()
fly(swan)
3.2 封装
向外部隐藏不必要的细节:无需知道对象的构造就能使用它,多态则是无需知道类型
3.3 继承
创建一个与之很像的类(可能只是新增了几个方法)
3.4 类
- self
指向对象本身,每次创建实例的时候,传入的第一个参数就是对象本身
-
隐藏
补充单下划线和双下划线的对比
- 双下滑线开头和结尾:Python的魔法函数,比如_init_()和__str__等等。不用要这种方式命名自己的变量或者函数。
- 双下划线开头:在前面加上“__”,表示它是私有成员,实例和子类不能访问。比如 “__xxx” 如果要访问得通过** _class__xxx 的方式进行访问**。虽然不能防止修改私有属性,但可以有效降低有意或者无意的修改。(其实dir(实例a)会有一个'_class_xxx'的)
- 单下划线开头:不能用from module import * 导入,其他方面和公有一样访问。
class Secretive:
def __inaccessible(self):
print("Bet you can't see me ...")
def accessible(self):
print("The secret message is:")
self.__inaccessible()
s = Secretive()
#s.__inaccessible()#不能访问,错误
s.accessible()#可以访问,在类里面
#s._Secretive__inaccessible()#在开头加上一个下划线和类名可以访问,但不应该这样做
- 类的命名空间
在class语句中的代码是特殊的命名空间,相当于全局
#类的所以成员都要访问这个空间,比如拿来计算实例的数量;
#相当于那个空间是全局的,默认情况下m1.members和m2.members都指向那个空间,但是m1.members = 'Two'后它的指向就变了
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
m1 = MemberCounter()
m1.init()
print(MemberCounter.members)#是1
m2 = MemberCounter()
m2.init()
print(MemberCounter.members)#是2
m1.members#是2
m2.members#是2
m1.members = 'Two'#m2.members不会变还是2,相当于这个是全局,重新命名的是另一个新空间吧,或者说=让m1.members指向了'two'
- 类的继承
内置方法:issubclass(子,父);
属性:子.__bases__找父类;
属性:对象.__class__找对象属于哪个类
多个类:按照广度优先寻找,按照括号继承顺序找
- 多个超类
如果有同名方法,会在class语句中按照顺序覆盖
- 接口
实现特定的方法,依赖于多态来调用这些方法
- 抽象基类
from abc import ABC, abstractmethod
class Talker(ABC):
@abstractmethod #@是装饰器,这里表示方法是抽象的,该类不应该实例化,职责是定义必须在子类中实现的方法:如果子类也不重写这个方法,则也不能实例化
def talk(self):
pass
- 其他和对象相关的方法
callable(object):判断对象是否是可调用的(如是否是函数或方法)
getattr(object,name[,default]):获取属性的值,还可提供默认值
hasattr(object, name):确定对象是否有指定的属性
isinstance(object, class):确定对象是否是指定类的实例
issubclass(A, B):确定A是否是B的子类
random.choice(sequence):从一个非空序列中随机地选择一个元素
setattr(object, name, value):将对象的指定属性设置为指定的值
type(object):返回对象的类型
dir(ogject):查看对象所有方法
- __new__:在创建对象时自动调用
- __init__:初始化时自动调用
- __del__:对象从内存中销毁时自动调用
- __str__:返回对象描述信息时,例如print()时调用
- __call__:平时自定义的函数、内置函数、类都是可调用对象,可以加()使用的,用callable(a)判断是不是可调用