Python基础

=== Python语言特点
Python 解释器可不止一种哦,有 CPython、IPython、Jython、PyPy 等。顾名思义,CPython 就是用 C 语言开发的了,是官方标准实现,拥有良好的生态,所以应用也就最为广泛了。而 IPython 是在 CPython 的基础之上在交互式方面得到增强的解释器(http://ipython.org/)。Jython 是专为 Java 平台设计的 Python 解释器(http://www.jython.org/),它把 Python 代码编译成 Java 字节码执行。

Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。
Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。
Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。
python动态语言:不指定变量类型;C++/Java:动态变量类型

=== 数据类型
Python3 中有六个标准的数据类型:
Number(数字)
String(字符串)
List(列表)
Tuple(元组)
Set(集合)
Dictionary(字典)

Python3 的六个标准数据类型中:
不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

Python3 支持 int、float、bool、complex(复数)。
在Python 3里,只有一种整数类型 int,表示为长整型,没有 python2 中的 Long。

判断变量类型:
isinstance 和 type 的区别在于:
type()不会认为子类是一种父类类型。eg:type(A()) == A
isinstance()会认为子类是一种父类类型。eg:isinstance(B(), A)

以下划线开头的标识符是有特殊意义的。以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 from xxx import * 而导入。
以双下划线开头的 __foo 代表类的私有成员,以双下划线开头和结尾的 __foo__ 代表 Python 里特殊方法专用的标识,如 __init__() 代表类的构造函数。
根据Python docs的说明,_object和__object的作用域限制在本模块内。
详见:https://blog.csdn.net/qq_31821675/article/details/78022862

bool型:
Python 中布尔值使用常量 True 和 False 来表示。
1、在数值上下文环境中,True 被当作 1,False 被当作 0
2、其他类型值转换 bool 值时除了 ''、""、''''''、""""""、0、()、[]、{}、None、0.0、0L、0.0+0.0j、False 为 False 外,其他都为 True

round函数慎用:
当个位为奇数,小数部分>=0.5入,其余为舍
当个位为偶数,小数部分>0.5入,其余为舍。

decimal 模块提供了一个 Decimal 数据类型用于浮点数计算,拥有更高的精度。
>>> import decimal
>>> decimal.getcontext().prec=4 # 指定精度(4位小数)
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1429')
>>> with decimal.localcontext() as ctx: # 小数上下文管理器
... ctx.prec=2
... decimal.Decimal('1.00') / decimal.Decimal('3.00')
...
Decimal('0.33')

浮点数与分数的转换:
from fractions import Fraction
f=2.5
z=Fraction(*f.as_integer_ratio())
x=Fraction(1,3) //分子,分母
float(x)

Python中一切都是对象,对象比较可以用 == 或者 is。
== 比较的是两个对象的内容是否相等,默认会调用对象的 __eq__() 方法。
is 比较的是两个对象的 id 是否相等,也就是是否是同一个对象,是否指向同一个内存地址。

Python 处于对性能的考虑,内部作了优化,对于整数对象,把一些频繁使用的整数对象缓存起来,保存到一个叫 small_ints 的链表中。在 Python 整个生命周期中,任何需要引用这些整数对象的地方,都不再重新创建新的整数对象,范围是 [-5,256]。(-5临界值没错,但256有问题)

0b1101:二进制
0o12:八进制
0x12:十六进制
bin(127)、oct(127)、hex(127):十进制数转成其他进制.
int('11101', base=8):将其他进制转成十进制

not > and > or:优先级高低

将单行长代码分行;

print(1,2,sep=":",end=" ") # sep将多个输出去变量间隔开,end末尾输出
input() #等待用户输入

r"你好啊 " # r表示不转义会原样输出字符串

字符串格式化:
print ("我叫 %s 今年 %d 岁!" % ('小明', 10))
print('{}网址: "{}!"'.format('菜鸟教程', 'www.runoob.com'))

字符串和list均有统计某个元素出现次数的方法count

以空格缩进控制代码片段范围

if 表达式:
pass
elif 表达式:
pass
else:
pass

enumerate()遍历迭代对象,同时返回索引位置和对应值

同时遍历两个或更多的序列,可以使用 zip() 组合

字符串正则匹配:
>>> import re
>>> re.findall(r'f[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> 'tea for too'.replace('too', 'two')
'tea for two'

=== 列表
通过id方法可测出Python列表是链式存储结构,并非顺序存储。

创建一定长度的空列表方法:[None]*10

列表的深拷贝:
方法1:list2 = list1[:]
方法2:list2 = list1.copy()
注:list2=list1非深拷贝

删除list元素的方法:
方法1:list[1:3] = []
方法2:del list[1:3]

list.remove(obj)
移除列表中某个值的第一个匹配项

reversed(list)、sorted(list)

列表推导示范。eg:newDict = {v:k for k, v in knights.items()}

列表可当做堆栈和队列使用.

=== 元组
tup1 = () # 空元组
tup2 = (20,) # 一个元素,需要在元素后添加逗号

tuple元素不可变有一种特殊情况,当元素是可变对象时。对象内部属性是可以修改的!tuple的不可变限制只是在一个纬度上:元素的类型。实现理解,tuple的元素所保存的内容(数值或内存地址)是不允许修改的,但地址映射的对象自身是可以修改的。

=== Dict
python中的字典是使用了一个称为散列表(hashtable)的算法(不具体展开),
其特点就是:不管字典中有多少项,in操作符花费的时间都差不多。
如果把一个字典对象作为for的迭代对象,那么这个操作将会遍历字典的键:
del dict['Name'] # 删除键 'Name'
dict.clear() # 清空字典
del dict # 删除字典
dict.pop(key) # 删除键值

=== Set
可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
无序:集合是无序的,所以不支持索引;字典同样也是无序的,但由于其元素是由键(key)和值(value)两个属性组成的键值对,可以通过键(key)来进行索引
元素唯一性:集合是无重复元素的序列,会自动去除重复元素;字典因为其key唯一性,所以也不会出现相同元素

创建一个含有多个元素的集合
>>> my_set = set(('apple','pear','banana'))

s.add( x )
将元素 x 添加到集合 s 中,如果元素已存在,则不进行任何操作。

s.update( x )
也可以添加元素,且参数可以是列表,元组,字典等. x 可以有多个,用逗号分开。

s.remove( x )
将元素 x 从集合 s 中移除,如果元素不存在,则会发生错误。
s.discard( x )
还有一个方法也是移除集合中的元素,且如果元素不存在,不会发生错误。

s.pop()
随机删除集合中的一个元素

=== 字符串内置方法:
isalpha()
如果字符串至少有一个字符并且所有字符都是字母则返回 True, 否则返回 False

isdigit()
如果字符串只包含数字则返回 True 否则返回 False.

lower()
转换字符串中所有大写字符为小写.

ljust(width[, fillchar])
返回一个原字符串左对齐,并使用 fillchar 填充至长度 width 的新字符串,fillchar 默认为空格。

upper()
转换字符串中的小写字母为大写

strip()
去除首尾空格

统计类:
from collections import Counter
Counter 是实现的 dict 的一个子类,可以用来方便地计数。
>>> c = Counter('abcasd')
>>> c
Counter({'a': 2, 'c': 1, 'b': 1, 's': 1, 'd': 1}) # 统计字符串中各个字符出现的次数

### 迭代器
import sys # 引入 sys 模块
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
while True:
try:
print (next(it))
except StopIteration:
sys.exit()

创建一个迭代器:把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
x = self.a
self.a += 1
return x

myclass = MyNumbers()
myiter = iter(myclass)
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

### 生成器
使用了 yield 的函数被称为生成器(generator)

什么情况下需要使用 yield?

一个函数 f,f 返回一个 list,这个 list 是动态计算出来的(不管是数学上的计算还是逻辑上的读取格式化),并且这个 list 会很大(无论是固定很大还是随着输入参数的增大而增大),这个时候,我们希望每次调用这个函数并使用迭代器进行循环的时候一个一个的得到每个 list 元素而不是直接得到一个完整的 list 来节省内存,这个时候 yield 就很有用。读取大文件时也很有用。
实际上的运行方式是每次的调用都在 yield 处中断并返回一个结果,然后再次调用的时候再恢复中断继续运行。yield有点像断点.

### 函数
func.__doc__ 显示函数的说明文档

函数和生成器当返回多个元素时,均是以元组形式返回。

显式指定函数的参数类型及返回值类型:
def function_demo(param_A: int, param_B: float, param_C: list, param_D: tuple) -> dict:
pass

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

默认参数必须放在最后。
python函数支持关键字参数(即传参时指定传给那个参数,此时可以是无序传参),C++/Java等不支持。
不定长参数:
def functionname([formal_args,] *var_args_tuple ):
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。

声明函数时,参数中星号 * 可以单独出现,例如:
def f(a,b,*,c):
return a+b+c
如果单独出现星号 * 后的参数必须用关键字传入。

还有一种就是参数带两个星号 **基本语法如下:
def functionname([formal_args,] **var_args_dict ):
加了两个星号 ** 的参数会以字典的形式导入。eg:
# 可写函数说明
def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vardict)
# 调用printinfo 函数
printinfo(1, a=2,b=3)


匿名函数:不能有return,可以没有参数,拥有自己的命名空间,一般只有一个表达式
sum = lambda arg1, arg2: arg1 + arg2
注意:相对于def函数,lambda是单一的表达式,而不是语句块
匿名函数作用:
1、程序一次行使用,所以不需要定义函数名,节省内存中变量定义空间
2、让程序更加简洁

函数的装饰器:在不改变当前函数的情况下, 给其增加新的功能
def log(pr):#将被装饰函数传入
def wrapper():
print("**********")
return pr()#执行被装饰的函数
return wrapper#将装饰完之后的函数返回(返回的是函数名)
@log
def pr():
print("我是小小洋")
pr()
回调函数和返回函数的实例就是装饰器。
详见:https://www.runoob.com/w3cnote/python-func-decorators.html

函数内可以访问全局变量,但不能更新(修改)其值!
a = 10
def sum ( n ) :
n += a
print ('a = ', a, end = ' , ' )
print ( 'n = ', n )
sum(3) # 不会报错

a = 10
def sum ( n ) :
# 解决办法:加上global a
n += a
a = 11
print ('a = ', a, end = ' , ' )
print ( 'n = ', n )
sum(3) # 报错UnboundLocalError: local variable 'a' referenced before assignment

作用域:
global 关键字会跳过中间层直接将嵌套作用域内的局部变量变为全局变量。
nonlocal 只能修改外层函数的变量而不能修改外层函数所引用的全局变量。eg:
x = 0
def outer():
global x
x = 1
def inner():
nonlocal x
x = 2
print(x)
inner()
outer() # 报错SyntaxError: no binding for nonlocal 'x' found
print(x)

### 模块
sys.argv 是一个包含命令行参数的列表。
sys.path 包含了一个 Python 解释器自动查找所需模块的路径的列表。

一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。
if __name__ == '__main__':


导入语句遵循如下规则:如果包定义文件 __init__.py 存在一个叫做 __all__ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
_all__ = ["echo", "surround", "reverse"]


### 读写文件:

f.readline():会从文件中读取单独的一行(包括换行符)。换行符为 ' '。f.readline() 如果返回一个空字符串, 说明已经已经读取到最后一行。
f = open("/tmp/foo.txt", "r")
str = f.readline()
print(str)
f.close()

f.readlines(): 将返回该文件中包含的所有行。

另一种方式是迭代一个文件对象然后读取每行:这个方法很简单, 但是并没有提供一个很好的控制。
f = open("/tmp/foo.txt", "r")
for line in f:
print(line, end='')
f.close()

如果要写入一些不是字符串的东西, 那么将需要先进行转换:
f = open("/tmp/foo1.txt", "w")
value = ('www.runoob.com', 14)
s = str(value)
f.write(s)
f.close()

推荐方式:
with open('test.txt', 'w', encoding='utf-8') as f:
f.write('test')

通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。

### 异常处理

方式1:
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise #抛出异常:raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。eg:raise Exception('x 不能大于 5。x 的值为: {}'.format(x))

方式2:
try:
f = open(arg, 'r')
except IOError:
print('cannot open', arg) # 发生异常时执行的代码
else:
print(arg, 'has', len(f.readlines()), 'lines') # 没有发生异常时执行的代码
f.close()
finally:
f.close() # 不管有没异常都会执行的代码(一般用来释放资源,但推荐用with)


### 面向对象:
self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的。

类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。
类的专有方法:
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__str__:打印对象
# 类运算符重载需要重写的方法
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
...

继承:
class DerivedClassName(BaseClassName1):
class DerivedClassName(Base1, Base2, Base3):
需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。

静态方法: 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。
普通方法: 默认有个self参数,且只能被对象调用。
类方法: 默认有个 cls 参数,可以被类和对象调用,需要加上 @classmethod 装饰器。
class Classname:
@staticmethod
def fun():
print('静态方法')

@classmethod
def a(cls):
print('类方法')

# 普通方法
def b(self):
print('普通方法')
Classname.fun()
Classname.a()

静态方法和类方法的区别:
Python会自动绑定类方法的第一个参数,类方法的第一个参数(通常建议参数名为 cls)会自动绑定到类本身;但对于静态方法则不会自动绑定。
主要体现在继承上。类B继承自类A,A定义了静态方法func1()和类方法func2(),B直接继承两个方法,则调用func1()时B.func1()和A.func1()结果完全相同;但B.func2()和A.func2()可能不同。

python实现的一系列排序方法:
https://www.runoob.com/python3/python3-examples.html

函数别名:某个参数设置固定值
from functools import partial
def subtraction(x, y):
return x - y
f = partial(subtraction, 4) # 4 赋给了 x
print(f(10))


元类、__new__、__call__:(待细究)
元类中, "__new__" 会在你定义类的时候执行, 只执行一次, 如果有两个类使用了这个元类, OK, 会执行两次;
__call__会在你每次实例化的时候调用, 其实和Foo.__new__是一样的, 意思是, 如果你的Foo定义了__new__, 元类中的__call__便不会执行;
因为Foo是元类Singleton创建出来的类,可以认为Foo是Singleton的实例对象。所以每次Foo()的时候都会去调用__call__。而在__call__中我们拿到已经创建好的实例对象。不就是单例吗。。
详见:https://segmentfault.com/q/1010000007818814

namedtuple:继承自tuple
namedtuple弥补了tuple的这一缺陷,使得你可以像使用对象属性那样去访问数据
Book = namedtuple('Book', ['name', 'price', 'count'])
book1 = Book(name='python', price=100.0, count=10)
print book1.name
print book1.price
print book1.count

计算程序运行时间:
import time
start_time = time.time()
print(time.time()-start_time) # 单位s

===== 测试用例的写法:

class APITest1(unittest.TestCase):
    def test_func1(self):
        val1 = [1,2,3]
        val2 = [2,3,4]
        self.assertEqual(len(val1), len(val2))

    def test_func2(self):
        val1 = [1,2,3]
        val2 = [2,3,4]
        self.assertIsInstance(val1, list)

class APITest2(unittest.TestCase):
    def test_func1(self):
        val1 = [1,2,3]
        val2 = [2,3,4]
        self.assertEqual(len(val1), len(val2))

    def test_func2(self):
        val1 = [1,2,3]
        val2 = [2,3,4]
        self.assertIsInstance(val1, list)

def run():
    # Multiple processings:同时执行多个测试类, 但同一个测试类中函数是按名字字典序顺序执行的
    suite = unittest.TestSuite()

    # add Test Case
    suite.addTest(unittest.makeSuite(APITest1))
    suite.addTest(unittest.makeSuite(APITest2))

    runner = unittest.TextTestRunner()
    result = runner.run(suite)
    result_errors = result.errors
    result_failures = result.failures
    num_errors = len(result_errors)
    num_failures = len(result_failures)
原文地址:https://www.cnblogs.com/luckyboylch/p/12531955.html