Python 知识点拾遗

Python 高级知识点,如 == 和 is 的区别,位运算。

import 导入模块

import 搜索路径

1
2
3
>>> import sys
>>> sys.path
['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/home/liuhao/.local/lib/python3.5/site-packages', '/usr/local/lib/python3.5/dist-packages', '/usr/local/lib/python3.5/dist-packages/setuptools-38.4.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/flansible-1.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/Flask_RESTful-0.3.6-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/aniso8601-3.0.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/ansible-2.5.0-py3.5.egg', '/usr/local/lib/python3.5/dist-packages/suitable-0.10.1-py3.5.egg', '/usr/lib/python3/dist-packages']
  • 路径搜索

    • 从上面列出的目录里依次查找要导入的模块文件
    • '' 表示当前路径
  • 新增导入路径

1
2
sys.path.append('/home/itcast/xxx')
sys.path.insert(0, '/home/itcast/xxx') #可以确保先搜索这个路径

重新导入模块

模块被导入后,import module不能重新导入模块,重新导入需用

1
2
from imp import reload
reload(test) # 重新导入模块

== 和 is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a == b
True
>>> a is b
False

>>> a = 100
>>> b = 100
>>> a is b
True
>>> a == b
True

>>> a = 300
>>> b = 300
>>> a is b
False
>>> a == b
True

>>> a = '123'
>>> b = '123'
>>> a is b
True
>>> a == b
True
  • is 是比较两个引用是否指向了同一个对象(引用比较)也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。
  • == 用来比较判断两个对象的 value (值)是否相等
  • 类似于 Java 同样存在,比较引用还是比较真实值的问题
  • Python 在为数字分配内存时,按照数字的内容来分配内存,即 a = 5;b = 5时,Python 只对数字 5 分配一块内存空间,而不是对变量 a 和 b 各分配一块内存;(在 Python 交互式界面有内存池缓存机制,只适用于 -5~256,在 Python 脚本编程中则没有这个限制)

1)Python 中一切都是对象;
2)Python 中 None 是唯一的;

每个对象包含3个属性,id,type,value

  • id 就是对象地址,可以通过内置函数 id() 查看对象引用的地址。
  • type 就是对象类型,可以通过内置函数 type() 查看对象的类型。
  • value 就是对象的值。

如下脚本的输出会是什么(非 Python 交互式环境)?

1
2
3
a = 300
b = 300
print(a is b)

正确答案是 True。

是不是很惊喜 😏

位运算

  • & 按位与
  • | 按位或
  • ^ 按位异或
  • ~ 按位取反
  • << 按位左移
  • >> 按位右移

用途: 直接操作二进制、省内存、效率高

<< 按位左移

各二进位全部左移 n 位,高位丢弃,低位补 0

注意事项:

  • 左移 1 位相当于乘以 2,可以用于快速计算一个数乘以 2 的 n 次方( 8<<3 等同于 8*2^3)
  • 左移可能会改变一个数的正负性

>> 按位右移

各二进位全部右移 n 位,保持符号位不变

x >> n,x 的所有二进制位向右移动 n 位,移出的位删掉,移进的位补符号位 右移不会改变一个数的符号

注意事项:

  • 右移 1 位相当于除以 2
  • x 右移 n 位就相当于除以 2 的 n 次方,用途:快速计算一个数除以 2 的 n 次方(8>>3 等同于 8/2^3)

& 按位与

全 1 才 1 否则 0 :只有对应的两个二进位均为 1 时,结果位才为 1,否则为 0

| 按位或

有 1 就 1:只要对应的二个二进位有一个为 1 时,结果位就为 1,否则为 0

^ 按位异或

不同为 1:当对应的二进位相异(不相同)时,结果为 1,否则为 0

  1. 任何数和 1 进行 & 操作,得到这个数的最低位。即:数字&1 = 数字的二进制形式的最低位
  2. 位运算优先级

私有化

  • xx:公有变量
  • _x:单前置下划线,私有化属性或方法,from somemodule import * 禁止导入,类对象和子类可以访问
  • __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
  • __xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__,不要自己发明这样的名字
  • xx_:单后置下划线,用于避免与 Python 关键词的冲突
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person(object):
def __init__(self, age = 18):
# 私有化属性,无法从外部直接获取
self.__age = age

def setAge(self, age):
self.__age = age

def getAge(self):
return self.__age

p1 = Person()
# print(p1.__age) # 会报错
print(p1.getAge())

# 获取对象的所有属性和方法
print(dir(p1))

# 相当于为 p1 新分配一个 __age 属性
p1.__age = 20

# 获取对象的所有属性和方法
print(dir(p1))

print(p1.__age)
print(p1.getAge())
  • 运行结果
1
2
3
4
5
6
7
8
$ python private.py
18
['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getAge', 'setAge']

# 可以看到新增了一个新的属性
['_Person__age', '__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getAge', 'setAge']
20
18

可以看到 Python 对类的私有属性进行了重整,__age 变成了 _Person__age,因此无法直接获取到。

总结

  • 父类中属性名为 __xx 的,子类不继承,子类不能访问
  • 如果在子类中向 __xx 赋值,那么会在子类中定义的一个与父类相同名字的属性
  • _xx 的变量、函数、类在使用 from xxx import * 时都不会被导入

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法对参数进行检查,于是我们可以使用 get、set 方法来对属性进行设置和检查。

1
2
3
4
5
6
7
8
9
10
11
12
class Money(object):
def __init__(self):
self.__money = 0

def getMoney(self):
return self.__money

def setMoney(self, money):
if isinstance(money, int):
self.__money = money
else:
print("error: 不是整型数字")

但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。

有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?

Python 内置的 @property 装饰器就是负责把一个方法变成属性调用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Money(object):
def __init__(self):
self.__money = 0

@property
def xmoney(self):
return self.__money

@xmoney.setter
def xmoney(self, money):
if isinstance(money, int):
self.__money = money
else:
print("error: 不是整型数字")

@property 的实现比较复杂,我们先考察如何使用。把一个 getter 方法变成属性,只需要加上 @property 就可以了,此时,@property 本身又创建了另一个装饰器 @money.setter,负责把一个 setter 方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

1
2
3
4
5
6
7
8
>>> from private import Money
>>> m = Money()
>>> m.xmoney
0
>>> m.xmoney = 99
>>> m.xmoney
99
>>>

注意到这个神奇的 @property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过 getter 和 setter 方法来实现的。

@property 成为属性函数,可以对属性赋值时做必要的检查,并保证代码的清晰短小,主要有 2 个作用:

  • 将方法转换为只读
  • 重新实现一个属性的设置和读取方法,可做边界判定
hoxis wechat
一个脱离了高级趣味的程序员,关注回复1024有惊喜~
赞赏一杯咖啡
0%