Python基础
字符串和编码
ASCII编码,1字节;Unicode编码,2字节;UTF-8编码,可变长编码。
在计算机内存中统一使用Unicode编码,保存到硬盘或者传输时使用UTF-8编码。
ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符
格式化
在Python中,采用的格式化方式和C语言是一致的,用%实现,举例如下:
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael',1000000) #用%号隔开两部分
'Hi, Michael, you have $1000000.'
其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数:
print('%2d-%02d' % (3, 1))
print('%.2f' % 3.1415926)
list和tuple
list
list是Python内置的有序列表。可以理解成C语言中的数组,嵌套list理解成二维数组
l = [1, 2, 3, 4]
l.sort() #排序
len(l) #长度
l[-1], l[-1] #列表l的倒数第一第二个元素
l.append(“xiaoming”)
l.pop() #删除末尾元素
l.pop(index) #index为索引号,删除指定位置元素
l = [1, 3, “xiaoming”, [“jack”, 67]] #list中可以嵌套list,像二维数组的方式查看元素
tuple
元组,和list很相似,但一经初始化不能修改,也可以像C语言中的数组一样读取
t = (1, 3)
t = (1, 4, [“xiaoming”, “xiaoli”]) #tuple中不能修改的是t中包含的指向对象,该对象所指向的其他对象或者存储的数据可以改变
t = () #空元组
t =(1,) #若只有一个元素一定要加逗号,否则系统会认为t是其他类型的对象而不是元组对象
条件判断
age = 20
if age >=18:
print(“adult”)
elif age >=6:
print(“teenager”)
else:
print(“kid”)
循环
for
names = [“xiaoming”, “jack”, “rose”]
for name in names:
print(name)
for i in range(3,7): #range(3,7),产生3-6的数列3,4,5,6
print(i)
while
n = 1
while n < 11: #输出1,3,5,7,9
print(n)
n+= 2
break和continue
使用dict和set
dict
dict和C++中的map类似,采用key-value方式存储,存取效率高,占用空间大。另外list可以看成特殊的dict,只不过在list中key被固定成0,1,2,3…
d = {“michael”: 95, “bob”: 75}
d[“jack”] = “rose”
d[“liangshanbo”] = “zhuyingtai”
d.pop(“jack”)
“jack” in d #若d中有key “jack”,返回True
二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value:
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
set
Python中的set和C++中的set非常相似,如:集合中的元素不重复。set中存放的必须是不可变对象
s = set([1, 2, 3])
s = set([1, 3, [“jack”, “rose”]]) #报错
s.add(“xiaoming”)
s.remove(“xiaoming”)
函数
调用函数
数据类型转换
Python有内置的类型转换函数
>>> int("123")
123
>>> str(123)
'123'
>>> int("12.34")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() withbase 10: '12.34'
>>> float(12.34)
12.34
>>> bool(123)
True
>>> bool(None)
False
>>> bool("fwf")
True
函数名是指向一个函数对象的引用,完全可以把函数名赋值给另一个变量,相当于给这个函数起了一个别名:
>>> a = abs
>>> a(-123)
123
定义函数
定义函数
要使用def,依次写出函数名,左括号,参数名,右括号,冒号,最后在缩进块中编写函数体,函数的返回用return来返回。
# -*- coding: utf-8 -*-
def my_max(x,y):
ifx>y:
returnx
returny
还可以将函数定义在xxx.py中,调用之前用from xxx import my_max来导入my_max()函数
空函数
如果想定义一个什么也不做的函数,可以用pass语句
def nop():
pass
if age>19:
pass
参数检查
使用isinstance(obj,(type1,type2,…))
def my_max(x,y):
ifnot isinstance(x,(int,float)):
raiseTypeError(“参数类型错误”)
如果传入错误的参数,函数就会抛出错误
Traceback (most recent call last):
File "C:/Users/kepcum/PycharmProjects/untitled/test.py", line3, in <module>
my_type("1")
File "C:\Users\kepcum\PycharmProjects\untitled\my_def.py",line 8, in my_type
raise TypeError("参数类型错误")
TypeError: 参数类型错误
返回多个值
本质上返回的是一个tuple。接受多个返回值时,可以用一个变量,也可以用多个变量
def my_duozhi(x,y):
return x,y
r = my_duozhi(23,4)
print(r)
x,y = r
print(x,y)
print(r[0])
输出如下:
(23, 4)
23 4
23
函数的参数
位置参数
顾名思义,调用函数传入参数时和位置相关,必须传入相应参数、
默认参数
定义函数时,给出默认值。调用时可传入参数也可不传入。
def my_pow(x,n=2):
returnx**n
默认参数必须指向不变对象
要修改上面的例子,我们可以用None这个不变对象来实现:
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
可变参数
函数参数的个数是可变的,参数实际上可以用一个tuple或者list传进来。
def my_sum(*num):
sum= 0
forx in num:
sum+= x
returnsum
在调用时,python会自动先封装出一个list或者tuple,我们调用时只需传入多参数即可
>>> my_sum([1,2,3,4]) #手动组装list会报错:int类型和list类型无法做+运算
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_sum
TypeError: unsupported operand type(s) for+: 'int' and 'list'
>>> my_sum(1,2,3,4)
10
>>> my_sum(*[1,2,3,4]) #这才是正确的传参方式
10
关键字参数
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
>>> def person(name,age,**other): #定义函数
... print("name:",name,"age:",age,"others:",other)
...
>>>person("tx",22,{"addr":"shandong","tel":"136"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positionalarguments but 3 were given
>>>person("tx",22,**{"addr":"shandong","tel":"136"})
name: tx age: 22 others: {'addr':'shandong', 'tel': '136'}
>>>person("tx",22,city="liangshan",tel="136") #关键字参数,直接传(参数名=参数)
name: tx age: 22 others: {'city':'liangshan', 'tel': '136'}
命名关键字参数
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
def person(name,age,*,city,tel):
print(name,age,city,tel)
>>> person("tx",22) #未传入命名关键字参数时,会报错
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
TypeError: person() missing 2 requiredkeyword-only arguments: 'city' and 'tel'
>>>person("tx",22,tel="136",city="liangshan") #命名关键字参数顺序打乱,不影响正常调用
tx 22 liangshan 136
>>>person("tx",22,tel="136",city="liangshan",school="sdust") #传入未命名的关键字参数会报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() got an unexpectedkeyword argument 'school'
命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。
使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:
def person(name, age, city, job):
#缺少 *,city和job被视为位置参数
pass
参数组合
Python中定义函数,参数的定义顺序必须是:必选参数,默认参数,可变参数,命名关键字参数,关键字参数。注意:默认参数在前,可变参数在后;命名关键字参数在前,关键字参数在后。
比如定义一个函数,包含上述若干种参数:
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw ={'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
最神奇的是通过一个tuple和dict,你也可以调用上述函数:
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d':99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
所以,对于任意函数,都可以通过类似func(*args,**kw)的形式调用它,无论它的参数是如何定义的。
尾递归
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。
高级特性
切片
list、tuple
简单来说,就是截取list或者tuple的一部分。
>>>L=["a","b","c","d","e","f","g","h"]
>>> x=L[0:3]
>>> x
['a', 'b', 'c']
>>> y=L[-5:]
>>> y
['d', 'e', 'f', 'g', 'h']
>>> z=L[-5:-1]
>>> z
['d', 'e', 'f', 'g']
>>> t=tuple(range(1,101))
>>> t1=t(0:10:2) #语法错误
File "<stdin>", line 1
t1=t(0:10:2)
^
SyntaxError: invalid syntax
>>> t1=t[0:10:2] #对于tuple切片时,仍使用[]。三个参数:第一个为起始下标,第二个为终止下标的后一个位置,第三个为步长,默认参数为1。
>>> t1
(1, 3, 5, 7, 9)
字符串
字符串可看作由字符组成的list,仍可使用切片操作。
>>> s="hello,what is yourname?"
>>> s
'hello,what is your name?'
>>> s[:7]
'hello,w'
>>> s[-5:]
'name?'
>>> s[::3]
'hlwtso m'
迭代
当我们使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行,而我们不太关心该对象究竟是list还是其他数据类型。
>>> d={"a":1,"b":2, "c":3}
>>> for key in d: #遍历关键字
... print(key,d[key])
...
a 1
b 2
c 3
>>> for v in d.values(): #遍历值
... print(v)
...
1
2
3
>>> for k,v in d.items(): #遍历dict中的item
... print(k,v)
...
a 1
b 2
c 3
>>> for ch in"123456789":
... print(ch)
另外,可以通过collections模块的Iterable类型
>>> from collections importIterable
>>> isinstance([1,2,3],Iterable)
True
>>>isinstance("1",Iterable)
True
>>> isinstance(123,Iterable)
False
可以通过enumerate,把list,tuple变成索引-元素树,然后用for循环进行遍历
>>> for i,val inenumerate([1,2,3,4]):
... print(i,val)
...
0 1
1 2
2 3
3 4
>>> t=(1,2,3,4)
>>> for i,val in enumerate(t):
... print(i,val)
...
0 1
1 2
2 3
3 4
在for循环中,可以同时引用多个变量
>>> for x,y in((1,1),(2,4),(3,9)):
... print(x,y)
...
1 1
2 4
3 9
列表生成式
>>> [x*x for x in range(1,10)]
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x*x for x in range(1,10) ifx%2==0]
[4, 16, 36, 64]
>>> l=[]
>>> for x in range(1,10):
... l.append(x*x)
...
>>> x
9
>>> l
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> l=[range(1,10)]
>>> l
[range(1, 10)] #不能生成list,用法错误
>>> l=list(range(1,10)) #可以生成list
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9]
两层循环
>>> [m+n for m in "abc"for n in "xyz"]
['ax', 'ay', 'az', 'bx', 'by', 'bz', 'cx','cy', 'cz']
列出当前目录下的所有文件和目录名,可以通过一行代码实现:
>>> import os
>>> l=[d for d inos.listdir(".")]
>>> l
['.idea', 'my_def.py', 'test.py', 'venv','__pycache__']
>>> dir
<built-in function dir>
>>> l=[x*x for x in range(1,10)]
>>> l
[1, 4, 9, 16, 25, 36, 49, 64, 81]
可以使用两个变量来生成列表
>>>d={"a":1,"b":2,"c":3}
>>> [k+"="+v for k,v ind.items()]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
TypeError: must be str, not int
>>> [k+"="+str(v) fork,v in d.items()]
['a=1', 'b=2', 'c=3']
把列表中的所有字母变为大写
>>>l=["hello","world"]
>>> l=[x.upper() for x in l]
>>> l
['HELLO', 'WORLD']
面向对象编程
类和实例
1、 类是抽象的创建实例的模板。实例是具体的对象,各个实例间数据互相独立、互不影响;
2、 方法是与实例绑定的函数,和普通函数不同,可以直接访问实例的数据;
3、 通过实例调用方法,就直接操作了对象内部的数据,但无需知道方法内部的实现细节;
4、 Python是动态语言,同一类的不同实例可能拥有不同的变量。
eg:
'''
类中方法之间留一个空行
类定义结束后留两个空行
'''
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def get_grade(self):
if self.score >= 90:
return 'A'
if self.score >= 60:
return 'B'
return 'C'
stu = Student('tx', 87)
stu.age = 22
print('\nname:%s\nage:%s\ngrade:%s' %(stu.name, stu.age, stu.get_grade()))
访问限制
1、 简单的来说就是将成员变量定义为私有,并通过set()、get()方法来访问和修改。
2、 在成员变量前加两个下划线就可以了,如:name变为__name
3、 Python本身没有任何机制阻止你干坏事,一切全靠自觉。
class Student(object):
def __init__(self, name, gender):
self.name = name
self.__gender = gender
def set_gender(self, gender): #可以避免实例的gender属性被修改为不合法的形式
if gender == 'male' or gender == 'female':
self.__gender = gender
pass
def get_gender(self):
return self.__gender
# 测试:
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
print('测试失败!')
else:
bart.set_gender('female')
if bart.get_gender() != 'female':
print('测试失败!')
else:
print('测试成功!')
继承和多态
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
class Animal(object):
def run(self):
print('animal is running...')
class Dog(Animal):
def run(self):
print('dog is running')
def run_twice(ani):
ani.run()
ani.run()
a = Animal()
b = Dog()
print('b is animal?', isinstance(b,Animal))
run_twice(a)
run_twice(b)
运行结果:
b is animal? True
animal is running...
animal is running...
dog is running
dog is running