python的对象类型不需要声明,python的对象一律使用引用来标记
x=10
s="string"
python的每一个对象有一个id,使用id()
可以获取对象的id
is
关键字可以用于判断两个对象的id是否相等
==
用于判断两个对象的内容是否相等,这与is
是不同的
a=10
b=20
c=b
d=20
print(a is b)
print(c is b)
print(d is b)
print(a==b)
print(b==c)
print(d==b)
python的变量名仅仅是一个名字,名字可以引用任意类型的对象
a=10
print(a)
a="string"
print(a)
a=[1,2,3]
print(a)
del()
可以解除变量名与对象的引用
python有六种标准的数据类型 分别是
- 数字
- 字符串
- 元组
- 列表
- 集合
- 字典
其中1-3类型的对象均不可变,4-6可修改
数字包含integer、float、bool、complex
x=1 #整数的精度是任意的
y=6.25
a,b=True,False
c=10+6j
可以通过type()
查询对象的类型
对象在指定时创建
销毁对象由GC自动完成,程序员无法主动销毁
在for
语句中,存在一个较为犯错的问题,例如
i = 0
for i in range(0,10):
...
print(i)
如果是其他语言例如c++
,那么循环中的i
与外部的i
应该是独立的,但这里,他们是同一个变量名
python的名字搜索顺序为,局部->非局部->全局->内建
另一个,如果名字出现在=
左边,那么在局部中他是创建了一个局部变量,而不是赋值给全局变量,如果希望赋值给全局变量,则需要使用global
counter=0
def f():
global counter
counter+=1
按照程序编写的顺序自上而下执行
if语句可以实现条件分支,可以使用的关键字是if
,elif
,else
x=10
if x<10:
print("condition 1")
elif x>100:
print("condition 2")
else :
print("condition 3")
注意,:
是不可或缺的
python中的循环使用while
实现
i=0
while i<10:
print(i)
同样的,python也支持break
与continue
python中的for
用于迭代,它通过迭代器进行遍历
x=[1,2,3]
for i in x :
print(i)
可以通过iter()
创建一个迭代器对象,该函数接受的对象必须是可迭代的
只要实现了__iter__()
和__next__()
的对象就是一个可迭代对象
__iter__()
返回迭代器本身,__next__()
返回下一个容器的下一个元素,直到结尾抛出StopIteration
异常
class T :
i=0
n=0
def __init__(self,n):
self.n=n
def __iter__(self):
return self
def __next__(self):
if self.i<self.n :
x=self.i
self.i=self.i+1
return x
else :
raise StopIteration
t=T(10)
for i in t :
print(i)
python的运算符基本与c相似
特别的有//
表示整除,/
将永远返回浮点数
**
可以计算幂
逻辑运算符使用and
、or
、not
in
与not in
可以测试成员是否存在与容器中
l=[1,2,3,4,5]
print(1 in l)
print(10 in l)
is
与is not
用于测试对象的地址是否相同,即是否是同一个对象
id()
可以得到对象的地址,a is b
实际上等价于id(a)==id(b)
//TODO
函数使用def
定义
def function_name (argument):
do something
python不能指定参数的类型,并且所有的传递都是类似于c语言通过指针传递参数
python中传递的参数是否可修改需要看对象是否可修改
def fun1 (x):
x=20
def fun2 (y):
y[0]=1
a=10
l=[0]
fun1(a)
fun2(l)
print(a,l)
类似于c语言的指针,将x赋值20事实上是创建了一个值为20的整数对象,然后将x指向这个新的对象
而修改y[0]是将y[0]指向了值为1的对象,因而改变了y指向的对象
void fun1(int *x)
{
int *p=malloc(sizeof(*p));
*p=20;
x=p
}
struct T
{
int y;
};
void fun2(struct T *t)
{
t->y=1;
}
python的函数可以指定参数默认指向的对象
def fun(a,b=1,c=2): pass
在指定了默认参数后,后续的参数也必须有默认的参数
值得注意的是,默认参数所指向的对象是同一个对象,这在默认对象是可变对象时需要注意
def f(a=0,l=[]):
l.append(a)
return l
f(1)
f(2)
l=f(3)
print(l)
这段代码最终l为[1,2,3]
解决这一问题的方案是在函数内部重新指向一个新的对象
def f(a,l=None):
l=[]
l.append(a)
return l
默认参数的原理是将函数参数指向一个对象,因此也可以这么写
i=10
def f(x=i):
print(x)
i=0
这个函数的x默认指向值为10的整数对象
重载需要解决的问题是函数功能相同,但参数的类型可能不同,或者参数的个数不确定
对于类型问题,python并不能指定参数的类型,也就是可以传递任意类型的参数
而参数个数问题可以通过缺省参数实现
一种用于实现类似重载的方式为,使用isinstance()
函数,用于判断对象类型,例如
def f(x,y):
if isinstance(y,int):
return x+y
elif isinstance(y,(float,str)):
return x+int(y)
else :
raise TypeError
python可以指定参数名调用函数,这与c语言的结构体初始化类似
def f(age,name):pass
f(name="John",age=22)
指定参数名后可以不依赖参数的顺序
def f(x,*args):
print(x)
for i in args:
print(i)
通过在变量名前添加*
实现不定长参数,参数以元组的方式导入
如果不定长的参数已经存在于元组或列表中,那么需要解压缩参数
解压缩参数在视觉上相当于去掉[]
或()
,因此也能用在其他地方 //待考证
l=[1,2,3,4,5]
f(10,*l)
对于字典,需要使用**
解压缩
//TODO
python的匿名函数功能用于返回一个小的函数对象
sum = lambda a,b : a+b
print(sum(1,2))
def f()->"a string" :
print("Annotations:", f.__annotations__)
将类的实例称为对象,类本身也是对象
python
的所有成员都是public
的
python的成员可在任意时刻创建,例如
class T:
def __init__(self,name="",age=0):
self.name=name
self.age=age
t=T("John",22)
__init__()
是构造函数,它的第一个参数表示类的实例自身,相当于c++的this指针,在调用时不需要传入
self.name
直接创建了一个名为name
的属性,该属性是每个实例对象独有的
甚至可以在类对象创建之后进行绑定,例如
x = T()
x.othername=0
类T在定义时内部的函数并没有othername
这一成员,但仍然可以在任意时刻绑定指定的对象
不过,在没有引用任何对象之前,第一次出现的成员名会导致错误
python
的所有成员函数都是virtual
的
python
中类的方法的第一个参数会传入自身的引用,在调用时会被忽略
class MyClass :
"""a doc attribute""" # __doc__ 文档字符串
i=12345 #所有类的实例共享
def __init__(self,name="a class"): #构造函数
self.name=name
def f(self):
print(self.name)
类可以通过编写某些特定名称的函数来重载运算符,例如重载加法
class T :
def __init__(self,re=0,im=0):
self.re=re
self.im=im
def __add__(self,rhs):
return T(self.re+rhs.re,self.im+rhs.im)
def __str__(self):
return str(self.re)+"+"+str(self.im)+"i"
a=T(1,2)
b=T(3,4)
print(a+b)
__add__()
方法用于重载+
,并且+
左边的类型必须是T
,右侧可以任意,如果想右侧的类型是T
,而左侧任意,则需要重写__radd__()
,另外还有复合赋值运算符如+=
,对应的函数名是__iadd__()
.
__add__(self,rhs) self + rhs 加法
__sub__(self,rhs) self - rhs 减法
__mul__(self,rhs) self * rhs 乘法
__truediv__(self,rhs) self / rhs 除法
__floordiv__(self,rhs) self //rhs 取整除
__mod__(self,rhs) self % rhs 取模(求余)
__pow__(self,rhs) self **rhs 幂运算
__lt__(self,rhs) self < rhs 小于
__le__(self,rhs) self <= rhs 小于等于
__gt__(self,rhs) self > rhs 大于
__ge__(self,rhs) self >= rhs 大于等于
__eq__(self,rhs) self == rhs 等于
__ne__(self,rhs) self != rhs 不等于
__and__(self,rhs) self & rhs 位与
__or__(self,rhs) self | rhs 位或
__xor__(self,rhs) self ^ rhs 位异或
__lshift__(self,rhs) self <<rhs 左移
__rshift__(self,rhs) self >>rhs 右移
__neg__(self) -self 负号
__pos__(self) +self 正号
__invert__(self) ~self 取反
__getitem__(self,i) x=self[i] 索引/切片取值
__setitem__(self,i,v) self[i]=v 索引/切片赋值
__delitem__(self,i) del self[i] del语句删除索引/切片
__str__
方法用于返回对象的字符描述,一般print
方法中会用到,已到达输出的目的
__iter__
与__next__
用于迭代器,例如设计一个简单的自增1的range
,命名为onerange
class onerange:
def __init__(self,begin=0,end=0):
self.begin=begin
self.end=end
def __iter__(self):
return self
def __next__(self):
if self.begin < self.end:
r=self.begin
self.begin+=1
return r
else :
raise StopIteration
另一种方法是使用生成器,生成器可以快速地创建一个迭代器
def nrange(begin,end,step=1):
while begin < end :
yield begin
begin+=step
yield
与return
类似,会返回值,只是如果下次继续调用该函数时,不是重新执行,而是会从yield
之后的语句再开始执行
与列表表达式类似,只是将[]
替换为()
,相对于列表推导式,生成器表达式可节省内存
l=(i*i for i in range(0,10))
print(l)
for i in l:
print(i)
模块是包括 Python 定义和声明的文件。文件名就是模块名加上 .py
后缀。模块的模块名(做为一个字符串)可以由全局变量 __name__
得到(如果通过py run.py
执行,那么__name__
会被设置成"__main__"
)。
import
可以引入模块名,例如在example.py
文件中有一个add()
函数,则在另一个py
文件中导入的方式如下
import example
print(example.add(10,20))
import
可以写在任意位置,只要在使用前声明即可
重命名写法如
import numpy as np #模块重命名 使用如 np.exp(-1)
该语句可以直接导入另一个模块的名字
from example import add
print(add(10,20))
其他写法如
from other import * #导入模块,名字直接使用
模块中的可执行语句一般用来初始化模块,在import
该模块时会开始执行
解释器先在当前目录中搜索 ,如果没有找到的话,接着会到 sys.path
变量中给出的目录列表中查找
内置函数 dir()
用于按模块名搜索模块定义,它返回一个字符串类型的存储列表
import dir #导入模块,使用方法如 dir.func()
from dir import dir.module
//TODO
列表使用[]
表示
l=[1,2,3]
l.append(4) #向列表对象末尾添加一个元素
sub=l[1:2] #返回一个新的子列表 范围为左闭右开
sub2=l[:2] #左下标默认0
sub3=l[2:] #右下标默认len(l)
sub4=l[:] #左右下标均默认,相当于一份l的浅拷贝
x=sub[-1] #负数表示逆序顺序
del l[0] #解除列表对象下标为0的元素的引用
ex=l+[1,2,3]#生成一个拼接后的列表
l+=[4,5] #末尾添加
l.pop() #解除末尾绑定,可指定下标
l[0:2]=[-1,-2]#区间替换
python列表的[]
运算符实际上是内置的__getitem__()
函数,它可以接受整型下标,也可以接受一个slice
对象,即带有:
运算符可以创建一个该对象,该对象的格式为begin:end:step
,一般为左闭右开区间
列表推导式
l=[x**2 for x in range(1,10)]
由于列表推导式会产生一个列表对象,如果需要更高效率,并且只是希望用于迭代可以用生成器表达式,即将[]
改为()
,如
g=(x**2 for x in range(1,10))
()
元组不可变
empty=()
single=123, #单个元素的元组后面跟一个','
double=1,2
triple=(1,2,3)
set()
set
支持并、交、差、对称差集运算,分别使用| & - ^
{key:value}
dict()
字典由键:值组成,键必须是不可变对象
tab={1:1,2:4,3:9}
print(tab[2])
tab[4]=16
x={x:x**2 for x in range(1,10)}
stu={"john":1,"tony":32,"jack":39,"tom":18,"peter":9}
print("john" in stu)
stu["abby"]=29 #向字典添加一个键值对
del std["jack"]#删除"jack"
xstu=stu.items() #返回一个(key,value)的列表(该列表是dict_items类型的,不是内置列表)
字符串可以使用" "
或''
表示
r"\n"
可以消除转义
""" ... """
可以实现多行字符串,如果想消除换行可以在行尾添加一个\
s="this is "+"a string" #拼接字符串
字符串是不可变对象
切片操作参考列表
目前还有一种f-string
,类似于f"this is a f-string"
,他可以将变量输出,如
x=10
s="string"
print(f"the x is {x} ,and s is {s}")