python基础语法 整理

语句和变量

语句折行

Python中, 如果一个语句被小括号, 中括号, 大括号包起来, 是可以跨行书写的
这样格式化的写一个字典, 在字典元素很多的时候会显得很清晰.

server = {
    'ip' : '127.0.0.1',
    'port' : 80
}

如果没有用括号包起来, 可以使用 \ 来换行

if x == 1 and \
    y == 1:
    do_something

双引号(")和单引号(’)字符串, 都不能折行, 但是三引号(’’’/""")可以折行

print ''' hello,
how are you? '''

使用 ; 可以把多个语句写到同一行. 但是强烈不建议这么做

print 'haha'; print 'hehe'

问题:一行代码多长合适?一个屏幕内能显示就行
有一部分公司指标:80个字符


缩进规范

在下列代码中,我们第三四行的print前面空4或者8 都是可以的
但是不能写成,前面空四个,后面不空四个–》错误的缩写

num = 10
if num == 0:
    print('hehe')
    print('hehe')

多重赋值(链式赋值)

可以同时给多个变量赋相同的值
x = y = 1


多元赋值

x,y = 10,20
print(x,y)
输出:10 20
延伸:交换变量
a = 10
b = 20
tmp = a
a = b
b = tmp

int a = 10;
int b = 20;
a = a + b;
b = a - b;
a = a - b;

int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;
a = a ^ b;

python:
x, y = 10, 20
x, y = y, x

增值赋值

+= -= *= /= %= **=
<<= >>= &= ^= |=


作用域和生命周期

Python中, def, class(我们后面会讲), lamda(我们后面会讲) 会改变变量的作用域
def : 创建函数
class:创建一个类
if, else, elif, while, for, try/except(我们后面会讲) 不会改变变量的作用域

for num in range(0,10):
    print(num)

print("out for: ",num)
输出:0-9(竖着)    和 out for:  9
def func():
    x = 10
    return x

print(x)
NameError: name 'x' is not defined
提示:x这个值找不到

locals 这个函数也是一个内建函数,能够帮助我们查看当前作用域里面
都能访问到那些变量

def func():
    x = 10
    y = 12
    if x == 10:
        print(locals())
    return x

func()
输出:{'x': 10, 'y': 12}


def func():
    x = 10
    return x

func()
print(locals()) #此时的 locals相当于打印全局变量

关于Python的变量的生命周期, 这个不需要程序猿操心, Python提供了垃圾回收机制自动识别一个变量的
生命周期是否走到尽头, 并自动释放空间(详情我们稍后再讲)

延伸:现如今大部分都有垃圾回收机制
除了C++ ,dart语言 不支持


特殊标识符,,也就是一些特殊变量名

特殊变量名一般有两类:
Python使用下划线(_)作为变量的前缀和后缀, 来表示特殊的标识符
_xxx表示一个 “私有变量”, 使用 from module import * 无法导入

python里面不太讲究这个私有或者不私有,虽然支持但是很少见到

xxx (前后一个下划线), xxx (前后两个下划线) 一般是系统定义的名字.
我们自己在给变量命名时要避开这种风格. 防止和系统变量冲突

打印python中的一些内置变量
print(locals())
输出:{'__name__': '__main__', '__doc__': None, 
'__package__': None,
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000275A1066CD0>,
 '__spec__': None, '__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>, 
'__file__': 'c:\\Users\\wyw15\\Desktop\\python代码\\testpython_2\\test.py', 
'__cached__': None}

文档字符串

写注释对于提升程序的可读性有很大的帮助.
前面我们介绍了 # 来表示单行注释.
对于多行注释, 我们可以使用 三引号(’’’/""") 在函数/类开始位置表示.
这个东西也被称为 文档字符串

import calc
print(calc.add.doc)

help(calc.add)
文档字符串不仅可以给函数,也可以给类来用
也可以给模块来用

模块
help(calc)


对象和类 的进一步探讨

一切都是对象: 整数,函数,模块,,,

如何判定一个东西是否为对象?取id,或者取类型
id是一个对象的身份标识
如果能取到这个id,说明他就是对象

import calc
print(id(calc))
输出:2077796269248
说明calc这个模块本质上也是一个对象
也可以用类型
import calc
print(type(calc))
输出:<class 'module'>

一个Python的对象, 包含三部分信息:
身份: 每一个对象都有一个唯一的身份标识自己.
实用内建函数id可以看到这个标识的具体的值.
类型: 对象的类型决定了对象保存什么样的值,
可以进行什么样的操作, 以及遵守什么样的规则. 实用内建函
数type可以查看对象的类型. 本质上就是把对象分分类.
值: 表示对象中具体保存的内容. 有些对象的值可以修改,
有些对象的值不能修改, 这个称为对象的 “可变性”


理解对象和引用

a = 2
b = 3
a = 2

python 中对于对象的处理,对于这个变量的处理和C语言差别很大,和java很像

这里的a和b都是引用,第一个 2 才是持有内存的变量主题
a和b只是一个标签而已

按照我们C语言中的理解, a = 2 , 相当于先创建一个变量名a,
a就是一个篮子(给a分配了内存空间), 然后
把数字2装到a这个篮子中. 但Python中完全不是这样的.

当我们执行 a = 2 的时候,
我们首先要找到 imteger class,找到创建一个整数对象的图纸
也就是整数对应的那一个类
找到图纸之后,我们要按照图纸创建一个变量,开辟一块内存
于是我们的内存中多了一块这样的区域
这个区域有三部分: 1.id 2.type 3.value
这个过程只是有一个 2 的过程,还没有赋值
赋值:把a这个变量名当作一个标签,然后往这块内存中一贴

python中 2 才是这个变量的本体
而c语言中a 才是这个变量的本题,2只是往a里面填充内容
python正好与之相反

讨论 :b = 3
b = 3 我们又在内存中,按照imteger class这样赋值,
在创建一个新的区域,在这个新的区域同样包含:id type value
只不过这个value = 3,我们又有一块新的内存
b= 3 ,也就是把b 这个标签贴到 3 上

讨论: b = 2
意思是:将b这个标签从3 上面取下来,然后贴到 2 上面(a指向的那个2)
即:a和b都指向这个2,
3 去哪了?因为没有标签贴到3 上面
3 被垃圾回收装置给回收了

注意:C++和这个思路有冲突,不好理解
java和这个思路是一样的

延伸: 如果下来执行:b+=1

a = 2
b = 3
print(id(a))
print(id(b))
b = 2
print(id(a))
print(id(b))
b+=1
print(id(a))
print(id(b))
输出:
2329240889680
2329240889712
2329240889680
2329240889680
2329240889680
2329240889712

为什么python要学java,而不是 C++
C++中的赋值相当于深拷贝
a = 100
b = a
相当于 内存中存了两份 100
java和python 相当于浅拷贝
a和b都是100的引用,内存中只存了一份100

垃圾回收装置(GC) 劣势?
1.开销较大 始终要有后台线程时刻扫描你的内存
时刻关注那些内存需要回收,,
一旦涉及大规模的 GC 极有可能导致程序卡顿
我们将这个卡顿称为:STW stop the world
现在java很成熟,以至于能把 STW这个控制在一毫秒之内
相比之下,python没有做的这么好,
一旦除法GC就会出现卡顿

综上所述:可以理解一些
python中的 int 其实是不可变类型的变量
即:你无法修改一个已经存在的int对象的值,你只能创建一个新的
类似的,python中许多都不能变
str float tuple

s = "hehe"
s[0] = a
不可运行

只能:
s = "hehe"
s = 'a' + s[1:]

python 中的可变对象:列表和字典

不可变的好处:
线程参数

python中的多线程是假的
看似创建了一个多线程,但实际上这些线程可能是串行执行
python为了保证线程安全,python有可变不可变对象
对于可变对象,还是要加锁,所以引入了:
GIL 全局解释器
每执行一行代码,都先加锁,执行完再解锁
然后加锁,解锁,锁你看上去没写,实际上一直存在


理解对象和类型

类型:将对象进行归类,有些对象可以归为一类,这一类对象都支持
一些通用的操作,有一些公用的特性,我们称之为相同类型
例如:整数都能进行加减乘除,字符串都能进行拼接,乘整数
列表都能append,这是我们对对象的功能进行了划分

Python是一种 动态强类型 编程语言
动态类型:一个变量在运行过程中,类型发生改变
静态类型: 一个变量在运行过程中,类型不能发生改变
强类型:越不支持隐形类型转换,类型越强
若类型:越支持隐形类型转换,类型越弱

隐式类型转换:

int a = 10;
int b = 20;
a = b;
在C++中可以这样写,最多有一个警告:b可能会被截断
在java中一定会出错,java的类型检查是很严格的

int a = 10;
bool b = false;
a = b;
C++ 中也不会出错,因为C++将false视为 0
java同样出错,说明java中的类型检查更严格
不同类型的变量不太支持隐式类型转化
所以java是强类型编程语言
c语言 是弱类型编程语言

标准类型

整型: 整数的范围没有上限
浮点型: 本质上是一个double双精度浮点数
并且浮点型也遵循 1745标准,
则:他也存在以前的问题,不能拿两个浮点数直接进行比较相等
浮点数是一个有限的内存空间,而我们数学中的小数往往无限长
我们用有限来存储无限,是有问题的
所以浮点数是有一定的误差的,
所以比较两个浮点数时,有时会出现错误
改进方法:做差,和0 进行比较
复数型: 10+ 10j
布尔型: True False
字符串
列表[]
元组()
字典{}
后三个在其它语言中都是按照库的方式体现的


其他内建类型

类型:(类型的类型),
s = 'hehe'
print(type(s))
输出:<class 'str'>

s = 'hehe'
a = type(s)
print(type(a))
输出:<class 'type'>

Null对象(None):
相当于java中的 null, C++中的 空指针
s = None
print(type(s))
<class ‘NoneType’>
NoneType他的变量只有一个,他表示无效变量

def func():
    print('hehe')

ret = func()
print(ret)
输出:
hehe
None

虽然我们没有写返回值,但是返回了一个None 这个对象
表示一个无效的,不存在的非法对象
和java中的null 是一个道理

文件
函数
模块


内建类型的布尔值

ret = None
if ret:
    print('1')
else:
    print('2')
输出:2
空字符串,0(所有值为零的数字),NoneFalse,空列表,空元组,空字典

对象值的比较

a = 10
b = 20
print(a == b)
比较a 和 b 的值
a = 10
b = 10
print(a is b)
a是不是b
True
还有 is not  

比较类型:

a = 10
b = 10
print(type(a) == type(b))
如何和C一样写类型
a:int = 10
加上这个能让代码可读性更高,但是没必要

a:int = 'hehe'
不会报错

a:int  =  10.0
b = 10
print(type(a) == type(b))
False

a = []
print(isinstance(a, list))
a = 100
print(isinstance(a, type(100)))
True
True

类型工厂函数

我们前面介绍了 int() 这个内建函数, 可以将一个字符串转换成一个整数.
其实是调用 int() 之后生成了一个整数类型的对象.
我们称这种函数为 “工厂函数” , 就像工厂生产货物一样

类似的工厂函数还有很多:
int(), float(), complex()
str(), unicode()
list(), tuple()
dict()
bool()

工厂函数:
工厂模式:这是我们设计模式的一种比较常见的模式
设计模式:它本质上是填编程语言的坑

单例模式:
线程安全的单例模式:
1.需要加锁 加锁的位置不能乱写
2.双重if环境 避免锁竞争判定
3.laolikuaiou 关键字

工厂:
工厂模式:它本质上是填编程语言的坑,即:构造函数的 坑
正常情况下,我们创建函数都是构造函数
但是构造函数有个重要的问题,函数名都是固定的
只能和类名是一样的,我们要想通过不同方式创建函数:重载
重载有问题:

有一个类 点(Point)
构造一个点需要:
笛卡尔坐标系:x y
Point(int x,int y);
极坐标:一个长度,一个角度
Point(int len,int radis);


Python不支持的类型

char, byte: 可以使用长度为1的字符串, 或者整数代替;
C++中有char 没有byte java中都有
指针: Python替你管理内存, 虽然id()返回的值接近于指针的地址, 但是并不能主动去修改;
int/short/long: 以前版本的Python中也是区分int和long的, 但是后来统一在一起了;
记住Python中的整数表示的范围, 只取决于你机器内存的大小.
float/double: Python的float其实就是C语言的double. Python设计者认为没必要支持两种浮点数


数字和运算

常用内置函数/模块
abs: 求一个数的绝对值.
divmod: 返回一个元组, 同时计算商和余数
a, b = divmod(10, 3)
print(a,b)
执行结果
3 1

str: 将数字转换成字符串.
round: 对浮点数进行四舍五入. round有两个参数,
第一个是要进行运算的值, 第二个是保留小数点后多少位

num = 10
num = str(num)
num = int(num)
print(type(num))
import math
for i in range(0, 10):
    print (round(math.pi, i))
执行结果
3.0
3.1
3.14
3.142
3.1416
3.14159
3.141593
3.1415927
3.14159265
3.141592654
整数进制转换: oct(), hex(), 参数是一个整数, 返回值是对应字面值的字符串.
num = 17
print(oct(num))   
print(hex(num))
0o21
0x11

math/cmath模块: 提供一些方便的数学运算的函数. math是常规数学运算; cmath是复数运算;
随机数random模块: 使用方法比较简单, 同学们自己回去自学
import random
print(random.randint(1,6))
生成一个[1,6)之间的数字


条件和循环

缩进和悬挂else

首先看一段C语言的代码(Java等其他语言也存在类似的问题)
if (x > 0)
    if (y > 0)
        printf("x and y > 0\n");
else
    printf("x <= 0\n");
我们期望 else 对应的代码, 执行 x <= 0 的逻辑

在C语言中, 如果不使用{ }来标明代码块, else会和最近的if匹配. 就意味着上面的else, 执行的逻辑其实是 y <= 0 .
在Python中, 就需要使用不同级别的缩进, 来标明, 这个else和哪个if是配对的
和 if x > 0 配对

if x > 0:
    if y > 0:
        print('x and y > 0')
else: 
    print('x <= 0')if y > 0 配对
if x > 0:
    if y > 0:
        print('x and y > 0')
else:
    print('x > 0 and y <= 0')

条件表达式
Python中并没有 ? : 这样的三目运算符, 理由是Python设计者觉得这个玩意太丑 T_T
取而代之的是, 一种叫做条件表达式的东西.
PS: 私以为, 这玩意更丑~ 但是预防同学们笔试面试被问到, 还是稍微提一下

x, y, smaller = 3, 4, 0
if x < y:
    smaller = x
else:
    smaller = y
上面这一段代码, 用条件表达式写作
smaller = x if x < y else y

和循环搭配的else

else不光可以和if搭伙, 还能和while, for搭伙

实现一个函数, 从列表中查找指定元素, 返回下标.
循环条件结束,且没有找到的时候执行else

def Find(input_list, x):
    for i in range(0, len(input_list)):
        if input_list[i] == x:
            return i
    else:
        return None
#实现一个函数, 打印出一个数的最大因子
def ShowMaxFactor(x):
    count = x / 2
    while count > 1:
        if x % count == 0:
            print 'largest factor of %d is %d' % (x, count)
            break
        count -= 1
    else:
        print x, "is prime"
for i in range(10, 20):
    ShowMaxFactor(i)

注意, 和循环搭配的else子句, 只会在循环条件不满足的时候才会执行
(对于for来说就是整个序列遍历完成).
如果循环中途break了, 仍然会跳过else


函数和可调用对象

函数定义和调用

我们可以在一个函数内部定义一个函数

def func1():
    def func2():
        print('hehe')
    func2()

func1()

python中的函数是一个对象,
那么他就可以作为函数的参数
也能作为函数的返回值

def func1():
    def func2():
        print('hehe')
    return func2 

a = func1()

函数的参数
def add(x,y):
return x+y

print(add(10,20))
print(add(‘hello’,‘world’))
print(add([1,2,3,],[4,5,6]))

默认参数
def add(x = 0, y = 1, z = 2):
return x+y+z

print(add(x = 10,z = 10))
输出:21

print(10,20,sep = ‘,’, end = ‘;’)
输出:10,20;


关键字参数

当我们有多个默认参数, 同时又只想传其中的某几个的时候,
还可以使用关键字参数的方式进行传参

例如内建函数 sorted (用来给序列进行排序), 函数原型为
sorted(iterable[, cmp[, key[, reverse]]])
函数有四个参数. 第一个参数表示传入一个可迭代的对象
(比如列表, 字符串, 字典等); 剩余三个参数都具备默认参数,可以不传

a = [1, 3, 4, 2]
print(sorted(a)) 
执行结果
[1, 2, 3, 4]

a = [1, 3, 4, 2]
print(sorted(a)) 
print(a)
输出:
[1, 2, 3, 4]
[1, 3, 4, 2]

sorted 可以排序 元组,列表,字符串

a = (1,3,4,7)
print(sorted(a)) 
print(a)
[1, 3, 4, 7]
(1, 3, 4, 7)
此处转换后的元组是一个列表

a = (1,3,4,7)
b = sorted(a)
c = tuple(b)
print(c)
(1, 3, 4, 7)

降序操作:
b = sorted(a,reverse= True)

按元素的绝对值排序
def Cmp(x, y):
    if abs(x) < abs(y):
        return -1
    elif abs(x) > abs(y):
        return 1
    else:
        return 0
a = [1, -3, 4, 2]
print (sorted(a, cmp = Cmp))
执行结果
[1, 2, -3, 4]

按字符串的长度排序
a = ['aaaa', 'bbb', 'cc', 'd']
print sorted(a, key = len)
# 执行结果
['d', 'cc', 'bbb', 'aaaa']

总结一下
和其他编程语言不同, Python的函数形参, 变量名字可不是随便写的. 尤其是这是一个默认参数的时候, 形
参名可能会随时被拎出来, 作为关键字参数协助函数调用时传入实参.
思考一下, 为什么C++不支持这样的语法呢? 其实理论上来讲也是完全可以实现的, 我们可以大胆猜测一下实现的思路
回忆C++函数调用过程(函数栈帧, C语言重点内容), 将参数按一定顺序压栈(倒腾ebp, esp), 然后跳转到函数
体所在的指令地址, 开始执行; 然后函数体内按照栈和偏移量来取参数.
那么, 只要编译器能够维护形参名字和对应的位置关系, 这样的映射, 保证函数调用时, 能够按照正确的顺序
把参数压栈, 就完成了这个过程

python的底层算法:Timsort 改进版本的归并排序


参数组

我们还可以将一个元组或者字典, 作为参数组, 来传给函数. 这样就可以帮助我们实现 “可变长参数”
通过将参数名前加一个 * 号, * 之后的内容表示是一个元组

def log(*msg):
    # msg 变成了一个列表    
    for m in msg:
        print(m,end = ',')
    
log(10,20,30)
10,20,30,

def log(**msg):
    # msg 变成了一个字典    
    for m in msg:
        print(m,msg[m])
    
log(x = 10, y = 20, z = 30)

函数重载

重载:
1.重载类型不同:python是动态类型,天然一个函数就可以传入不同类型
2.参数个数不同:python有默认参数和参数组这样的语法
则:python不需要支持重载,python参数规则功能是强于重载的


函数的返回值

通过return关键字返回一个对象.
如果没有return语句, 则返回的是None对象.
可以同时返回N个对象, 通过 , 分割(本质上是在返回一个元组)

def get_point():
    x,y = 10,20

a = get_point()
print(a)
打印出None

当我们用a,b来接受函数的返回值
如果打印其中一个,那么这个打印就会出错

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值