深拷贝和浅拷贝
深拷贝与浅拷贝的区别在于,当从原本的list复制出的list之后,修改其中的任意一个是否会对另一个造成影响,即这两个list在内存中是否储存在同一个区域,这也是区分深拷贝与浅拷贝的重要依据。
浅拷贝:A变量变化,B变量跟着改变
深拷贝:A变量变化,B变量不受影响
copy():对于list的第一层,是实现了深拷贝,但对于嵌套的list,仍然是浅拷贝。
old = [1,[1,2,3],3]
new = old.copy()
print('Before:')
print(old)
print(new)
new[0] = 3
new[1][0] =3
print('After:')
print(old)
print(new)
output:
Before:
[1, [1, 2, 3], 3]
[1, [1, 2, 3], 3]
After:
[1, [3, 2, 3], 3] #对于list的第一层(非嵌套层),实现了深拷贝,对于嵌套的list,仍然是浅拷贝。
[3, [3, 2, 3], 3]
通过for循环遍历,将元素一个个添加到新列表中。这也是一个浅拷贝方法,只对第一层实现深拷贝。
通过使用[:]切片,可以浅拷贝整个列表。同样的,只对第一层实现深拷贝。
完全深拷贝的实现:
如果用deepcopy()方法,则无论多少层,无论怎样的形式,得到的新列表都是和原来无关的,这是最安全最有效的方法。
import copy
old = [1,[1,2,3],3]
new = copy.deepcopy(old)
print('Before:')
print(old)
print(new)
new[0] = 3
new[1][0] = 3
print('After:')
print(old)
print(new)
output:
Before:
[1, [1, 2, 3], 3]
[1, [1, 2, 3], 3]
After:
[1, [1, 2, 3], 3]
[3, [3, 2, 3], 3]
列表
列表方法
list.append(obj)
在列表末尾添加新的对象
list.count(obj)
统计某个元素在列表中出现的次数
list.extend(seq)
在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.index(obj)
从列表中找出某个值第一个匹配项的索引位置
list.insert(index, obj)
将对象插入列表
list.pop([index=-1])
移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
list.remove(obj)
移除列表中某个值的第一个匹配项
list.reverse()
反向列表中元素
list.sort( key=None, reverse=False)
对原列表进行排序
list.clear()
清空列表
list.copy()
复制列表
模块
一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
当我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?这就涉及到Python的搜索路径,搜索路径是由一系列目录名组成的,Python解释器就依次从这些目录中去寻找所引入的模块。查看Python搜索路径:
>>> import sys
>>> sys.path
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']
>>>
from … import
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中。
from … import *
把一个模块的所有内容全都导入到当前的命名空间,但是那些由单下划线(_)开头的私有函数或变量不在此例。大多数情况, Python程序员不使用这种方法。为引入的其它来源的命名,很可能覆盖了已有的定义。如果不同模块包含了函数名相同的函数,或者是与自己编写得函数名相同将会导致混乱,而且在 debug 时还不容易发现。
包
这里给出了一种可能的包结构(在分层的文件系统中):
sound/ 顶层包
__init__.py 初始化 sound 包
formats/ 文件格式转换子包
__init__.py 有__init__.py才被认为是一个包
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ 声音效果子包
__init__.py
echo.py echo模块
surround.py surround模块
reverse.py reverse模块
...
filters/ filters 子包
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。
目录只有包含一个叫做 init.py 的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做 string)不小心的影响搜索路径中的有效模块。
import sound.effects.echo
# 这将会导入子模块:sound.effects.echo。 他必须使用全名去访问:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
#还有一种导入子模块的方法是:
from sound.effects import echo
#这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
echo.echofilter(input, output, delay=0.7, atten=4)
#还有一种变化就是直接导入一个函数或者变量
from sound.effects.echo import echofilter
#这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:
echofilter(input, output, delay=0.7, atten=4)
注意当使用from package import item这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。
如果使用形如import item.subitem.subsubitem这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。
关于导入模块,自己写的程序,自己也可以把它保存下来,以后需要的时候导入使用,例如下面所示。
我有个代码名称为 test1.py,它的所在路径为 D:\test 下面。那我只需要完成以下步骤就可以把它作为模块 import 到其他代码中了。
import sys
sys.path.append("D:\\test")
类
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
class MyClass:
i = 12345 #类变量
def f(self):
return 'hello world'
类有一个名为__init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用,像下面这样:
def __init__(self):
self.data = []
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问,只能在类内部访问,以两个下划线打头
__weight = 0
类的继承,Python也支持多继承
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
s = student('ken',10,60,3)
s.speak()
方法重写,如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法。
类的私有属性(两个下划线开头):__private_attrs:声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类的私有方法(两个下划线开头):__private_method:声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。
类的专有方法(魔法方法)(前后两个下划线):
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
但是以单个下划线打头的函数或变量为相对此模块本身为私有的,外界无法调用。
静态方法无隐含参数,主要为了类实例也可以直接调用静态方法。
逻辑上类方法应当只被类调用,实例方法实例调用,静态方法两者都能调用。主要区别在于参数传递上的区别,实例方法悄悄传递的是self引用作为参数,而类方法悄悄传递的是 cls 引用作为参数。
获取帮助
import math
dir(math) #查看模块下所有函数
['__doc__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'acos',
'acosh',
'asin',
'asinh',
'atan',
'atan2',
'atanh',
...
help(math.log) #help查看帮助
Help on built-in function log in module math:
log(...)
log(x[, base])
Return the logarithm of x to the given base.
If the base not specified, returns the natural logarithm (base e) of x.
math.log.__doc__ #查看函数文档字符串
log(x[, base])
Return the logarithm of x to the given base.
If the base not specified, returns the natural logarithm (base e) of x.
import random
print(random.__file__) #查看源码的位置
C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\lib\random.py
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问。
常用函数
dec=12
bin(dec)) #十进制转二进制0b1100
oct(dec)) #十进制转八进制0o14
hex(dec)) #十进制转十六进制0xc
ord() #字符转化为ASCII码
chr() #ASCII码转化为字符
str.upper() # 把所有字符中的小写字母转换成大写字母
str.lower() # 把所有字符中的大写字母转换成小写字母
str.capitalize() # 把第一个字母转化为大写字母,其余小写
str.title() # 把每个单词的第一个字母转化为大写,其余小写