【学习笔记】python——变量、运算符、数据类型及位运算

1.1 Python简介

  Python 是由 Guido van Rossum 在八十年代末和九十年代初,在荷兰国家数学和计算机科学研究所设计出来的。Python 本身也是由诸多其他语言发展而来的,这包括 ABC、Modula-3、C、C++、Algol-68、SmallTalk、Unix shell 和其他的脚本语言等等。像 Perl 语言一样,Python 源代码同样遵循 GPL(GNU General Public License)协议。现在 Python 是由一个核心开发团队在维护,Guido van Rossum 仍然占据着至关重要的作用,指导其进展。Python 2.7 被确定为最后一个 Python 2.x 版本,它除了支持 Python 2.x 语法外,还支持部分 Python 3.1 语法。

1.2 学习目标

1、变量、运算符与数据类型

  • 注释
  • 运算符
  • 变量和赋值
  • 数据类型转换
  • print()函数

2、位运算

1.3 变量、运算符与数据类型

1.3.1 注释

  学过编程语言的应该都知道每种编程语言都会有注释,当然了python也会有注释,只不过和C++/JAVA的注释不太一样。

pythonC++/JAVA
单行注释#//
多行注释''' ''' 或者 """ """/* */

上面的单引号或者双引号不够明显,下面还是通过代码来演示一下。

# 是单行注释
print('Hello world')  #输出的就是Hello world

'''
这是夹在6个单引号之间的多行注释。
'''

"""
当然也可以将单引号换成双引号,但是两者不要混着用,要么就全部单引号,要么就全部双引号。
"""

''' ''' 或者 """ """ 表示区间注释,在三引号之间的所有内容被注释。

1.3.2 运算符
1.3.2.1 算术运算符
操作符名称示例
+1 + 1 = 2
-2 - 1 = 1
*3 * 4 = 12
/3 / 4 = 0.75
//整除3 // 4 = 0
%取余3 % 4 = 3
**2 ** 3 = 8

将上述例子输入的python当中进行验证:

print(1 + 1)  # 2
print(2 - 1)  # 1
print(3 * 4)  # 12
print(3 / 4)  # 0.75
print(3 // 4)  # 0
print(3 % 4)  # 3
print(2 ** 3)  # 8

  面的 %是要特别注意的。在不同编程语言中,它的计算公式可能是不一样的,意思就是说用这个符号在不同的编程语言中可能一样的式子最后得出的结果不一样。例如,(-11)%5在python中计算的结果是4,而在C中计算的结果则是-1。

  1. C/Java语言除法采用的是趋零截尾(事实上,C89对于除数或被除数之一为负数情况的结果是未定义的;C99才正式确定了趋零截尾),即truncate除法。它们的取模运算符是%,并且此运算符只接受整型操作数。一个规律是,取模运算的结果的符号与第一个操作数的符号相同(或为0)。因此(-11)%5=-11-[(-11)/5]*5=-11-(-2)*5=-1。
  2. Python语言除法采用的是趋负无穷截尾,即floor除法。它的取模运算符也是%,并且此运算符可以接受浮点操作数。一个类似的规律是,取模运算的结果的符号与第二个操作数的符号相同。因此(-11)%5=-11-[(-11)/5]*5=-11-(-3)*5=4。这里需要注意的是,Python 3.x中"/“运算符的意义发生了变化,”/“产生的结果将不会再进行截尾;相应的”//"运算符的结果才会进行截尾。

这边就不解释太多了,感兴趣的可以自己去百度不同编程语言中取模运算符的差异

1.3.2.2 比较运算符
操作符名称示例
>大于2 > 1
>=大于等于2 >= 4
<小于1 < 2
<=小于等于5<= 2
==等于3 == 4
!=不等于3 != 5

同样将上述例子带入python中进行验证:

print(2 > 1)  # True
print(2 >= 4)  # False
print(1 < 2)  # True
print(5 <= 2)  # False
print(3 == 4)  # False
print(3 != 5)  # True
1.3.2.3 逻辑运算符
操作符名称示例
and(3 > 2) and (3 < 5)
or(1 > 3) or (9 < 2)
notnot (2 > 1)
print((3 > 2) and (3 < 5))  # True
print((1 > 3) or (9 < 2))  # False
print(not (2 > 1))  # False

  这边可能有些人会把 与 或 非 以为是 && || !,这三个是C++/JAVA当中的写法,要注意一下。

1.3.2.4 位运算符
操作符名称示例
~按位取反~4
&按位与4 & 5
|按位或4 | 5
^按位异或4 ^ 5
<<左移4 << 2
>>右移4 >> 2

  这边需要点二进制相关的知识了。等会在后面会讲到位运算的相关知识。在这里就先将上述例子带入到python当中运行查看效果。

print(bin(4))  # 0b100
print(bin(5))  # 0b101
print(bin(~4), ~4)  # -0b101 -5
print(bin(4 & 5), 4 & 5)  # 0b100 4
print(bin(4 | 5), 4 | 5)  # 0b101 5
print(bin(4 ^ 5), 4 ^ 5)  # 0b1 1
print(bin(4 << 2), 4 << 2)  # 0b10000 16
print(bin(4 >> 2), 4 >> 2)  # 0b1 1

  这边数字前面的0b只是一种标记符,表示这是一个二级制数值。当然也有100B,这种写在最后面的。这边也扩展下,十六进制就是0x,或者是在最后面加H。上述代码中的bin() 函数表示将某个10进制数表示成二进制数。

1.3.2.5 三元运算符

  说到三元运算符,可能大部分人会想到 ? : 不过python当中没有这个运算符,不过有一个类似的。small = x if x < y else y,它的意思就是如果x < y 那么small = x,否则small = y。就是取x和y中的较小值。

x, y = 4, 5
small = x if x < y else y
print(small)  # 4
1.3.2.6 其它运算符
操作符名称示例
in存在'A' in ['A', 'B', 'C']
not in不存在'h' not in ['A', 'B', 'C']
is"hello" is "hello"
is not不是"hello" is not "hello"

这些运算符也是挺实用的,举两个例子

letters = ['A', 'B', 'C']
if 'A' in letters:
    print('A' + ' exists')
if 'h' not in letters:
    print('h' + ' not exists')

# A exists
# h not exists

其实 innot in倒是挺容易理解的,那么可能会有人疑惑了, isnot is为什么需要呢,不是有 =!= 吗。其实这两个是有区别的。这边来简单解释下。

  • isis not是地址比较
  • =!= 是值比较

说到地址比较就要先引出python中id()这个函数,这个函数就是取出变量的地址的。接下来看一些例子

当比较的两个变量均指向可变类型时。

a = [1,2,3]
b = [1,2,3]
a == b  # 输出的肯定是true,因为值是一模一样的
a is b # 可能有人也会觉得输出的是true,但结果是false
id(a) # 3076010508L
id(b) # 3076166636L
# 用id()这个函数看出了 这两个值的地址是不一样的,因此是false

当比较的两个变量均指向不可变类型时

a = "hello"
b = "hello"
print(a is b, a == b)  # True True
print(a is not b, a != b)  # False False
# 那为什么这里用 is 也是相等的呢,其实很好证明,我们用id()函数输出一下地址就知道了。
id(a) # 2536490040752
id(b) # 2536490040752
# 所以知道为什么在这里是相等的了吧。

至于为什么上面 当两个类型不一样的时候,结果也不一样,这里就涉及到python的内存分配了。python为了提高内存利用效率对于一些简单的对象,如一些数值较小的int对象,字符串对象等,python采取重用对象内存的办法. 这里就简单解释下,感兴趣的可以自己去深究。下面作些简单的总结。

  1. is, is not 对比的是两个变量的内存地址
  2. ==, != 对比的是两个变量的值
  3. 比较的两个变量,指向的都是地址不可变的类型(int, str等),那么is,is not 和 ==,!= 是完全等价的。
  4. 对比的两个变量,指向的是地址可变的类型(list,dict,tuple等),则两者是有区别的。
1.3.2.7 运算符的优先级

在这里插入图片描述

  • 一元运算符优于二元运算符。例如3 ** -2等价于3 ** (-2)
  • 先算术运算,后移位运算,最后位运算。例如 1 << 3 + 2 & 7等价于 1 << (3 + 2)) & 7
  • 逻辑运算最后结合。例如3 < 4 and 4 < 5等价于(3 < 4) and (4 < 5)

【例子】

print(-3 ** 2)  # -9
print(3 ** -2)  # 0.1111111111111111
print(1 << 3 + 2 & 7)  # 0
print(-3 * 2 + 5 / -2 - 4)  # -12.5
print(3 < 4 and 4 < 5)  # True
1.3.3 变量和赋值
  • 在使用变量之前,需要对其先赋值。
  • 变量名可以包括字母、数字、下划线、但变量名不能以数字开头。
  • Python 变量名是大小写敏感的,foo != Foo。
1string = "Hello world!" # 是错误的,不能以数字开头
string1 = "Hello world!" # 是正确的
_string = "Hello world!" # 也是正确的
string= "Hello Python"
print(string)  # Hello Python

# 变量赋值
a = 1
b = 2
c = a + b # 3

# 字符串可以相加
string1 = "Hello"
string2 = "world!"
print(stirng1 + string2) # Hello world!
1.3.4 数据类型与转换
类型名称示例
int整型 <class 'int'>-876, 10
float浮点型<class 'float'>3.149, 11.11
bool布尔型<class 'bool'>True, False
# 整型
a = 1
print(a, type(a))
# 1 <class 'int'>  值为1, 类型为 int

Python 里面万物皆对象(object),整型也不例外,只要是对象,就有相应的属性 (attributes) 和方法(methods)。可以通过dir() 来查看。

b = dir(int)
print(b)

# ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__',
# '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__',
# '__float__', '__floor__', '__floordiv__', '__format__', '__ge__',
# '__getattribute__', '__getnewargs__', '__gt__', '__hash__',
# '__index__', '__init__', '__init_subclass__', '__int__', '__invert__',
# '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
# '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__',
# '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__',
# '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__',
# '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
# '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
# '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__',
# 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag',
# 'numerator', 'real', 'to_bytes']

当然,上面的属性和方法不需要记住,需要用到的时候再来查看就行了。现在来看一些例子。

# 将一个整数输出它的二进制数表示的方式,并求出长度
a = 1025
print(bin(a)) # 0b10000000001
print(a.bit_length()) # 11
# 浮点型
print(1., type(1.))
# 1.0 <class 'float'>
a = 0.00000023
b = 2.3e-7
c = 0.23
print(a)  # 2.3e-07
print(b)  # 2.3e-07
print(c)  # 0.23
# 可以看到当小数点位数过多后,会以科学计数法的方式表达

对于浮点数来说,可以通过round(x[,n])函数来控制小数点的位数,x是要操作的数,n是要保留几位小数。

print(round(0.5111, 3))
# 0.511
# 布尔型
# 布尔 (boolean) 型变量只能取两个值,`True` 和 `False`。当把布尔型变量用在数字运算中,用 `1` 和 `0` 代表 `True` 和 `False`。
print(True + True)  # 2
print(True + False)  # 1
print(True * False)  # 0

除了直接给变量赋值 TrueFalse,还可以用 bool(X) 来创建变量,其中 X 可以是

  • 基本类型:整型、浮点型、布尔型
  • 容器类型:字符串、元组、列表、字典和集合

只要给的X是非零数(不是整型 0 和浮点型 0. 和 空的变量 )bool(X) 就是 True,其余就是 False

print(bool(0), bool(1))
# False True
print(bool(''), bool('python'))
# False True
print(bool([]), bool([1, 2]))
# False True
1.3.4.1获取类型信息

获取类型信息type(object)

print(type(1))  # <class 'int'>
print(type(5.2))  # <class 'float'>
print(type(True))  # <class 'bool'>
print(type('5.2'))  # <class 'str'>

判断类型信息isinstance(object, classinfo)

print(isinstance(1, int))  # True
print(isinstance(5.2, float))  # True
print(isinstance(True, bool))  # True
print(isinstance('5.2', str))  # True

这里需要注意的是type(object)不考虑继承关系,而isinstance(object, classinfo)考虑继承关系。

1.3.5 print()函数

print(*objects, sep=' ', end='\n)'这里就列出几个常用的参数,object没什么好说的就是要输出的变量,而sep参数就是每个变量之间用什么分割(默认为空格),而end参数是最后一个参数的后面加上什么(默认输出完所有变量之后换行)。

print(1, 2) # 1 2 中间是空格隔开
print(1, 2, sep='*') # 1*2 中间是*隔开
print("hello")
print("world!")
# hello
# world!
# 默认是输出完之后换行,所以hello world!分两行显示了。
print("hello", end=' ')
print("world!")
# hello world!
# 修改了第一个print(),使输出完变量之后,用空格接上

2 位运算

2.1 原码、反码和补码

在学习原码、反码和补码之前,需要先了解机器数和真值的概念
机器数
  个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。那么,这里的 00000011 和 10000011 就是机器数。
真值
  因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

1、原码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

[+1]= 0000 0001

[-1]= 1000 0001

第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

[1111 1111 , 0111 1111]==>[-127 , 127]

2、反码
反码的表示方法是:

  • 正数的反码是其本身
  • 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
[+1] = [00000001]= [00000001][-1] = [10000001]= [11111110]

3、补码
补码的表示方法是:

  • 正数的补码就是其本身
  • 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
[+1] = [00000001]= [00000001]= [00000001][-1] = [10000001]= [11111110]= [11111111]

特别注意:在位运算中符号位也参与运算。

2.2 按位非操作~

~num的补码中的 0 和 1 全部取反(0 变为 1,1 变为 0)有符号整数的符号位在 ~ 运算中同样会取反。

# 无符号数
~ 1 = 0
~ 0 = 1

# 有符号数
00 00 01 01 -> 5
~
11 11 10 10 -> -6
-----------------
11 11 10 11 -> -5
~
00 00 01 00 -> 4

2.3 按位与操作&

只要有一个为0则结果为0,两个都为1则结果为1

1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

00 00 01 01 -> 5
&
00 00 01 10 -> 6
---
00 00 01 00 -> 4
2.4 按位或操作|

只要两个对应位中有一个 1 时就为 1

1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

00 00 01 01 -> 5
|
00 00 01 10 -> 6
---
00 00 01 11 -> 7
2.5 按位异或操作^

两个对应位不同时为1,否则为0

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

00 00 01 01 -> 5
^
00 00 01 10 -> 6
---
00 00 00 11 -> 3

特别注意:满足交换律和结合律

2.6 按位左移操作<<

num << inum的二进制表示向左移动i位,并且右边用0补齐,所得到的值。

00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88 
2.7 按位右移操作>>

num >> inum的二进制表示向右移动i位,并且左边用0不起,所得到的值。

00 00 10 11 -> 11
11 >> 2
---
00 00 00 10 -> 2 
2.8 利用位运算实现快速计算
n << 1 -> 计算 n*2
n >> 1 -> 计算 n/2,负奇数的运算不可用
n << m -> 计算 n*(2^m),即乘以 2 的 m 次方
n >> m -> 计算 n/(2^m),即除以 2 的 m 次方
1 << n -> 2^n

通过异或操作符^可以快速交换两个整数

a ^= b # a = a ^ b
b ^= a # b = b ^ a = b ^ a ^ b = a
a ^= b # a = a ^ b = a ^ b ^ a = b
# 因此达到交换两个整数的目的
2.9 利用位运算实现整数集合

一个数的二进制表示可以看作是一个集合(0 表示不在集合中,1 表示在集合中)。最右边算是第0位。
比如集合 {1, 3, 4, 8},可以表示成 01 00 01 10 10 而对应的位运算也就可以看作是对集合进行的操作。
元素与集合的操作:

a | (1<<i)  -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 从集合中删除
a & (1<<i)  -> 判断 i 是否属于该集合(零不属于,非零属于)

集合与集合的操作:

a 补   -> ~a
a 交 b -> a & b
a 并 b -> a | b
a 差 b -> a & (~b)
2.10 leetcode题实战

leetcode_136 只出现一次的数字

class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        ans = 0
        for i in nums:
            ans ^= i
        return ans


参考文献:
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值