Python学习笔记之基础语法

推荐网址:廖雪峰python教程官网

推荐书籍:《Python编程:从入门到实战》

安装:python安装和anaconda安装两种方式

推荐:Anaconda安装,它包含了python和其他数学工具包

一、数据类型与变量

整数、浮点数、字符串、布尔值、空值

注意python2和python3的差别

python2时:

1)print内容时可用可不用括号

2)除法3/2=1

python3时

1)Print一定要括号

2)3/2=1.5, 3//2=1

a='99'
print(type(a)) 
 #<class 'str'>

二、列表list和tuple

2.1 list

列表 由一系列按特定顺序排列的元素组成

list是一种有序的集合,可以随时添加和删除其中的元素,其中元素可以时任意类型

List=['Michael',12,False,['A','B','C']]
print(List)    
#['Michael', 12, False, ['A', 'B', 'C']]
# print(List[-1])
# List.append('Adam')
# List.insert(1, 'Jack')
# List.pop()
# List.pop(1)
List[1] = 'Sarah'
print(List) 
#['Michael', 'Sarah', 12, False, ['A', 'B', 'C'], 'Adam']
2.2 tuple
# 2. tuple
t = (1,2,3,'A')
print(t)

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改

如果要定义一个空的tuple,可以写成()

只有1个元素的tuple定义时必须加一个逗号,

它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的

t = (1)
t 
# 1
t = ('a', 'b', ['A', 'B'])
t[2].append('C')
t
#('a', 'b', ['A', 'B', 'C'])

三、字典dict和set

3.1 dict

Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度

d = {'Michael': 95, 'Bob': 75, 'Tracy': 85, 32:12}
print(d)
#{'Michael': 95, 'Bob': 75, 'Tracy': 85, 32: 12}
d['Adam'] = 67
d.pop('Bob')
d['Jack'] = 88
d['Michael']
d['Thomas']
'Thomas' in d

和list比较,dict有以下几个特点:

查找和插入的速度极快,不会随着key的增加而变慢; 需要占用大量的内存,内存浪费多。 而list相反:

查找和插入的时间随着元素的增加而增加; 占用空间小,浪费内存很少。 所以,dict是用空间来换取时间的一种方法。

3.2 set
# 2. set
s = set([1, 2, 3])

set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,

因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,看看是否会报错。

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,看看是否会报错

L=[1,2,3]
LL=['A', 'B', 6, 2,L]
s = set(LL)

四、条件判断和循环

4.1 if条件
	# 1. if条件
age = 30
if age >= 18
    print(1)
    print('adult')
elif age >= 6:
    print('teenager')
else:
    print('kid')

还需要注意一下if条件,只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False。

x=True
if x:
    print('True')
4.2 for 循环
# 2. for循环
sum = 0
for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
    sum = sum + x
print(sum)
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
for k,v in d.items():
    print(k,v)

#Michael 95
#Bob 75
#Tracy 85
#32 12
L=['A', 'B', 6, 2]
s = set(L)
print(s)
for sk in s:
    print(sk)

五、函数

Python的函数定义非常简单,但灵活度却非常大。 除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码

5.1 函数形式
# 1.函数形式
def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x
5.2 函数返回值
# 2.返回值
import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny,1
# x,y = move(1,3,3)
# print(x,y)
#实际返回类型
x,y = move(100, 100, 60, math.pi / 6)
# print()
5.3 函数参数
5.3.1 位置参数
# 3. 函数参数
# 3.1 位置参数
def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n

5.3.2 默认参数
# 3.2 默认参数
def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name) #  name: Amy
    print('gender:', gender) # gender: M
    print('age:', age) # age: 7
    print('city:', city) # city: Beijing
enroll('Amy','M',7)

从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意:

一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);

二是如何设置默认参数。
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。

使用默认参数有什么好处?最大的好处是能降低调用函数的难度。

#也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin'),
#意思是,city参数用传进去的值,其他默认参数继续使用默认值。
enroll('Bob', 'M', 7)
#name: Bob
#gender: M
#age: 7
#city: Beijing
enroll('Adam', 'M', city='Tianjin')
#name: Adam
#gender: M
#age: 6
#city: Tianjin

默认参数很有用,但使用不当,也会掉坑里。默认参数有个最大的坑,演示如下:

def add_end(L=[]):
    L.append('END')
    return L
add_end() #执行多次
# ['END', 'END', 'END', 'END']

原因解释如下:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

定义默认参数要牢记一点:默认参数必须指向不变对象

5.3.3 可变参数
# 3.3 可变参数
def calc(a,*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    print(a)
    return sum
 c = calc('abc', 1,2,3)
 print(c)
 #abc
 #30

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple

5.3.4 关键字参数
# 3.4 关键字参数
def person(name, age, **k):
    print('name:', name, 'age:', age, 'other:', k)
  # person('Michael', 30)
person('Adam', 45, gender='M', job='Engineer')
#name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

5.3.5 命名关键字参数
# 3.5 命名关键字参数
 def person(name, age, *, city, job):
    print(name, age, city, job)
  
 person('Jack', 24, city='Beijing', job='Engineer')
 #Jack 24 Beijing Engineer

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查

和关键字参数*kw不同,命名关键字参数需要一个特殊分隔符,*后面的参数被视为命名关键字参数

注意:
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

def person(name, age, *args, city, job):
    print(name, age, args,city, job)
person('Jack', 24,city='Beijing', job='Engineer')
# person('Jack', 24, 'Beijing', 'Engineer')
# Jack 24 () Beijing Engineer

由于调用时缺少参数名city和job,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

命名关键字参数可以有缺省值,从而简化调用:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)
person('Jack', 24, job='Engineer')
5.3.6 参数组合
# 3.5 参数组合
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)
f1(1,2)
f2(1,2,d=99)

参数组合

参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差

5.4 高阶函数
# 4 高阶函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回

六、高级特性

切片、迭代、列表生成式、生成器、迭代器

对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作

6.1 切片
# 1. 切片
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
# L[0:3]
# L[:]
# L[1:4]
# L[-2:]
L[-1]
6.2 迭代
# 2. 迭代
D={'A':1,'B':2,'C':3}
# for key in D:
#     print(key)
for i, value in enumerate(D):
    print(i, value)

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

6.3 列表生成式
# 3. 列表生成式
list(range(1, 11))

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

生成[1x1, 2x2, 3x3, …, 10x10]怎么做?方法一是循环:

L = []
for x in range(1, 11):
    L.append(x * x)
[x * x for x in range(1, 11)]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[x * x for x in range(1, 11) if x % 2 == 0]
# [4, 16, 36, 64, 100]
[m + n for m in 'ABC' for n in 'XYZ']
# ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
变换式:
for m in 'ABC':
    for n in 'XYZ':
        print(m + n)
 d = {'x': 'A', 'y': 'B', 'z': 'C' }
{v:k for k, v in d.items()}
# {'A': 'x', 'B': 'y', 'C': 'z'}
6.4 生成器 generator
# 4. 生成器
L = [x * x for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10)) # <generator object <genexpr> at 0x000001BB6BEDB6D0>

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator

#著名的斐波拉契数列(Fibonacci) 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
o = odd()
next(o)#多次循环试试

小结 generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

6.5 迭代器
# 5. 迭代器
from collections import Iterable
isinstance([], Iterable)

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

可以使用isinstance()判断一个对象是否是Iterable对象:

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的

七、模块

7.1 import导入
# 1. 使用模块 我们以内建的sys模块为例,编写一个hello的模块:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'Michael Liao'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':
    test()

当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量name置为main,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。类似Java的main函数#

7.2 作用域

在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。

(1) 正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;

(2) 类似xxx这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的author,name就是特殊变量,hello模块定义的文档注释也可以用特殊变量doc访问,我们自己的变量一般不要用这种变量名;

(3) 类似xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如abc,__abc等;

注: 之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量

def _private_1(name):
    return 'Hello, %s' % name

def _private_2(name):
    return 'Hi, %s' % name

def greeting(name):
    if len(name) > 3:
        return _private_1(name)
    else:
        return _private_2(name)

八、面向对象编程

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

仍以Student类为例,在Python中,定义类是通过class关键字:

8.1 类和实例
# 1. 类和实例
class Student(object):
    pass
bart = Student()
bart
#<__main__.Student at 0x27b7337b4e0>
Student
# __main__.Student

变量bart指向的就是一个Student的实例,后面的0x10a67a590是内存地址,每个object的地址都不一样,而Student本身则是一个类

可以自由地给一个实例变量绑定属性,比如,给实例bart绑定一个name属性

bart.name = 'Bart Simpson'
bart.name
# 'Bart Simpson'

一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的init方法,在创建实例的时候,就把name,score等属性绑上去

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score
bart = Student('Bart Simpson', 59)
bart.name
8.2 数据封装
# 2. 数据封装
def print_score(std):
    print('%s: %s' % (std.name, std.score))
print_score(bart)
8.3 访问限制
# 3.访问限制
bart = Student('Bart Simpson', 59)
bart.score
bart.score = 99
bart.score

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改

class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
    
    def __printone(self):
        print('test')
stu = Student('Aman',2)
stu.__printone()
bart = Student('Bart Simpson', 59)
bart.__name

可以给Student类增加get_name和get_score这样的方法

需要注意的是,在Python中,变量名类似xxx的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用name、score这样的变量名。

有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

#最后注意下面的这种错误写法:
bart = Student('Bart Simpson', 59)
bart.print_score()

bart.__name = 'New Name' # 设置__name变量!
bart.__name
8.4 继承和多态
# 4.继承和多态

当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

class Animal(object):
    def run(self):
        print('Animal is running...')
class Dog(Animal):
    pass

class Cat(Animal):
    pass     
dog = Dog()
dog.run()
#Animal is running...
cat = Cat()
cat.run()  
# Animal is running...
class Dog(Animal):

    def run(self):
        print('Dog is running...')

class Cat(Animal):

    def run(self):
        print('Cat is running...')


def run_twice(animal):
    animal.run()
    animal.run()       


run_twice(Animal())
#Animal is running...
#Animal is running...

run_twice(Dog())
#Dog is running...
#Dog is running...

run_twice(Cat())
#Cat is running...
#Cat is running...

class Tortoise(Animal):
    def run(self):
        print('Tortoise is running slowly...')
run_twice(Tortoise())
#Tortoise is running slowly...
#Tortoise is running slowly...
       

你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值