模块 模块名.py
(不应使用中文,这里仅做示范)如果是放在包里的:ercilan.模块名
这个包是一个目录,目录下需要有标识文件(可为空):__init__.py
。__init__.py
表示这个目录也是一个模块。 可以有多级目录,但如果是要作为包的都需要有 __init__.py
。 自己创建的如果与 Python 内部模块重名,则内部模块会被覆盖无法使用。 Python 模块的标准文件模板: 1 2 3 4 5 6 7 8 9 10 11 12 '本模块的文档注释' __author__ = '二次蓝' import sys if name == '__main__' : print ('使用命令行调用了' ) sys.exit()
sys 模块有一个 argv
列表变量,储存了调用模块时的命令行 的所有参数。第一个值是模块的文件名。比如命令行调用 1.py
模块带 参数1
,那么 sys.argv
:['1.py', '参数1']
sys.path
包含了解释器查找模块的所有目录。写多少个 import test
都只会导入一个 test 模块。 作用域 以 __
开头结尾的是特殊变量,自己一般不要使用这种命名; _xxx
和 __xxx
这样的函数或变量 就是非公开的(private),不应该被直接引用,比如 _abc
,__abc
等;因为 Python 并无限制访问权限,所以这种命名是一种约定俗成的习惯,应该遵守。 在类里面会将 __abc
修改为其他名字,间接实现私有。(单下划线没有) 安装第三方模块 更新 pip:python -m pip install --upgrade pip
镜像安装模块:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
使用 Anaconda Anaconda 是一个用于科学计算的 Python 发行版 ,支持 Linux, Mac, Windows, 包含了众多流行的科学计算、数据分析的 Python 包。
anaconda 英 [ˌænəˈkɒndə] 美 [ˌænəˈkɑːndə] n. 水蟒;蟒蛇
Miniconda 安装包可以到 https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/ 下载。
更新源修改 查看已设置软件源:
1 2 conda config --show # 在显示的配置中可以找到channels,-defaults为预设值
删除指定 url:conda config --remove channels url地址
添加更新源:
1 2 3 4 # 清华大学开源软件镜像 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
设置搜索时显示通道地址:
1 conda config --set show_channel_urls yes
清除索引缓存,保证用的是镜像站提供的索引:conda clean -i
anaconda | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
避免出现其他错误,在 anaconda prompt 里 更新一下所有工具包:
类 1 2 3 4 5 6 7 class Student (object ): job = 'student' def __init__ (self, name, age ): self .name = name self .age = age def get_age (self ): print (self .age)
__init__
函数相当于 java 中的构造器self
用来表示 java 中的 this
,是类的每个函数必需的第一个参数 实例化时只需要且必须要 传入 name
、age
注意 :与静态语言 Java 不同,动态语言 Python 可以对实例对象动态的添加不同的变量。因此一个类的不同实例可能有不同的属性/变量数量。1 2 stu1 = Student('小蓝' , 22 ) stu1.score = 99
类变量和成员变量 –> 类属性和实例属性 直接在 class 下面:job = 'student'
,这个是类的属性;self.name
是实例属性。
类的属性是所有实例可以修改的,大家共享一个。类似于 Java 的 static
。 访问类对象使用 Student.job
,无论在类内部还是外面,这样好使。 为一个类动态添加方法或属性也这么使用 Student.sing = ...
访问权限限制 将类的变量名前添加 __
即可变成私有变量(private)。
注意:变量名前后都有 __
的是特殊变量,可以访问,不是私有的 _
单下划线开头 Python 不会修改变量名,但是一般我们也不要去直接访问它多态 假设我们又写了两个子类 BoyStu 和 GirlStu,继承自 Student。
isinstance(BoyStu, Student)
为 True
。可以使用 type
鸭子类型:理解有这个类型就行了。然后知道下面加粗部分。 1 2 3 def run_twice (student ): student.run() student.run()
Java 中,调用方法需要传入对象需要为其父类或子类。而动态类型 Python 不同,只要有 run()
函数,就能运行。
动态语言的“鸭子类型”:一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。 其实也就是动态语言没有强制要求函数的参数类型 。有这个方法,就能运行起来。获取对象信息 查询判断变量类型: 1 2 3 4 5 6 value_type = type (o) types.FunctionType types.BuiltinFunctionType types.LambdaType types.GeneratorType
判断是不是这些类型的其中一种:
1 2 isinstance (lista, (list , tuple ))
获取对象的所有属性和方法:dir(o)
getattr(o, 'x', 404)
:获取对象 o 的 x 属性/方法,不存在返回值:404hasattr(o, 'x')
:判断对象 o 是否有 x 属性/方法setattr(o, 'x', 18)
:给对象 o 设置 x 属性为 18(当然也可以设置为方法,变量可以指向函数嘛)类:限制设置属性 限制 Student 类,只能绑定 name 和 age 属性:
1 2 class Student (object ): __slots__ = ('name' , 'age' )
注意:子类不会默认继承这个限制,就会无限制。- 在子类继续使用 __slots__
,那么子类的限制绑定就是父类的 __slot__
加上自己的 ___slot__
。 超出绑定:AttributeError: 'Student' object has no attribute 'height'
@property
装饰器可以将方法返回的值变成属性,方法名作为属性名;在这个方法里设置好对属性的检查等。
@property
放在一个方法前,方法的名字表示属性的名字。这个方式是该属性的 getter,返回一个值即可。1 2 3 4 5 @property def width (self ): return self ._width
这里返回了 self._width
,那么就需要在 setter 里设置这个值 这里写的代码是通过中间值 _width
来储存的属性 接下来是 setter 的设置,不设置这个的属性是一个可读属性。 1 2 3 4 @width.setter def width (self, value ): self ._width = value
完成,外部可以正常操作对象的属性 width: 1 2 3 4 o.width = 11 print (o.width)
虽然从理论上,self._width
的赋值是在 setter 里的,且外部也是这样的调用顺序。但是因为装饰器要生成 @width.setter
,所以是写在后头的。
类:多重继承 在类的设计时,优先考虑类的多重继承组合功能,而不是设计多层次复杂的单继承。 拓扑、C3算法
Python多重继承排序原理(拓扑、C3) - 简书
找的规则:没有被继承的(刚开始就是子类本身) 去掉这个类的所有联系,再找上一个(去掉的类括号内继承的父类里调) 括号里有多个,看他们定义位置,写在前面的优先继承;有被其他的继承了的类不能找。 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 class A (object ): def foo (self ): print ('A foo' ) def bar (self ): print ('A bar' ) class B (object ): def foo (self ): print ('B foo' ) def bar (self ): print ('B bar' ) class C1 (A ): pass class C2 (B ): def bar (self ): print ('C2-bar' ) class D (C1,C2): pass if __name__ == '__main__' : print (D.__mro__) d = D() d.foo() d.bar()
(标红表示确定了顺序,需要清空它的联系,划掉它)D ,继承自 C1、C2,这里面找;C1 写在前面,且 C1 没有再被继承,C2 等待; C1 括号里为 A ,且 A 没有再被继承; A 继承自 object,object 还被 B 继承了,不能找,到尽头了,切到等待的 C2;C2 括号里为 B ,且 B 没有再被继承; B 括号里为 object ,且没有再被继承; 。。。还是画图吧
1 2 3 (<class '__main__.D' >, <class '__main__.C1' >, <class '__main__.A' >, <class '__main__.C2' >, <class '__main__.B' >, <class 'object' >) A foo A bar
类:定制类 打印:__str__
、__repr__
1 2 3 4 5 def __str__ (self ): return 'Student object (name=%s)' % self .name __repr__ = __str__
__str__
是 Python 调用的 str()
函数。__repr__
是命令行模式下,敲一个变量直接回车显示的函数。相当于 Java 的 toString()
方法。 使得一个类可迭代:__iter__
、__next__
、raise StopIteration()
1 2 3 4 5 6 7 8 9 10 11 12 class Fib (object ): def __init__ (self ): self .a, self .b = 0 , 1 def __iter__ (self ): return self def __next__ (self ): self .a, self .b = self .b, self .a + self .b if self .a > 100000 : raise StopIteration() return self .a
按下标可取出:__getitem__()
1 2 3 4 5 6 7 class Fib (object ): def __getitem__ (self, n ): a, b = 1 , 1 for x in range (n): a, b = b, a + b return a
支持切片功能的按下标取出:__getitem__()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Fib (object ): def __getitem__ (self, n ): if isinstance (n, int ): a, b = 1 , 1 for x in range (n): a, b = b, a + b return a if isinstance (n, slice ): start = n.start stop = n.stop if start is None : start = 0 a, b = 1 , 1 L = [] for x in range (stop): if x >= start: L.append(a) a, b = b, a + b return L
slice
切片类型,有 start
、stop
属性。除此之外,需要实现与 Python 内置切片相符合的功能,还要做检查是否为负数,间隔取值等等。 __setitem__()
方法,把对象视作list或dict来对集合赋值。__delitem__()
方法,用于删除某个元素。__getattr__
:当调用实例对象的属性未找到时,Python 会调用这个方法。可以把一个类的所有属性和方法调用全部动态化处理 链式调用,【然后干啥?不太懂什么意思】 1 2 3 4 5 6 7 8 9 10 11 12 13 class Chain (object ): def __init__ (self, path='' ): self ._path = path def __getattr__ (self, path ): return Chain('%s/%s' % (self ._path, path)) def __str__ (self ): return self ._path __repr__ = __str__
试试:
1 2 >>> Chain().status.user.timeline.list '/status/user/timeline/list'
这样,无论 API 怎么变,SDK 都可以根据 URL 实现完全动态的调用,而且,不随 API 的增加而改变。???等到时候实际应用再理解吧 将实例对象作为函数对象:__call__
(这个对象可以 ()
运行) 1 2 3 4 5 6 7 8 9 10 class Student (object ): def __init__ (self, name ): self .name = name def __call__ (self ): print (f'我的名字是{self.name} .' ) s1 = Student('小蓝' )() s2 = Student('企鹅' ) s2()
变成了 Callable 对象 查看对象是否可被调用:callable(Student())
类:枚举类 创建枚举类 1 2 3 from enum import EnumMonth = Enum('Month' , ('Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' , 'Jul' , 'Aug' , 'Sep' , 'Oct' , 'Nov' , 'Dec' ))
Enum('类名', ('对象名1', '对象名2'))
它的值是按顺序从数字 1 开始增加 Month.__members__
是储存了所有对象的有序字典 OrderedDict,遍历:1 2 for name, member in Month.__members__.items(): print (name, '=>' , member, ',' , member.value)
1 2 3 4 5 6 7 8 9 10 11 from enum import Enum, unique@unique class Weekday (Enum ): Sun = 0 Mon = 1 Tue = 2 Wed = 3 Thu = 4 Fri = 5 Sat = 6
作用:每个常量都是 class 的一个不可更改的唯一实例 访问枚举类: 1 2 3 4 5 Month.Jan Month['Jan' ] Month(1 ) Month.Jan.value
类:元类 动态创建类 在 Java 中,类的类型是 class
,而 Python 中类的类型是 type
。 实例对象的类型是 ***类。
1 2 3 4 5 6 >>> print (type (Hello))<class 'type' > >>> print (type (h))<class 'hello.Hello' >
type()
还可以创建类!跟 class Hello(object):
的功能一样。
1 2 3 4 def fn (self, name='world' ): print ('hello' , name) Hello = type ('Hello' , (object ,), dict (greet=fn))
第一个参数是类的名字 第二个参数是继承的父类的元组(记得元组单个元素时的写法) 第三个参数是设置属性/方法的字典 实际上 class
定义类底层也是调用的 type()
方法。 元类,就是说,通过元类创建类,再通过类创建实例对象。 metaclass 是 Python 面向对象里最难理解,也是最难使用的魔术代码。基本上很少用到。
1 2 3 4 5 class ListMetaclass (type ): def __new__ (cls, name, bases, attrs ): attrs['add' ] = lambda self , value: self .append(value) return type .__new__(cls, name, bases, attrs)
TO BE CONTINUED