JakobHu 2019-06-27
type(2/2) float type(2//2) int
双斜杠是整除,出来的类型是int。单斜杠的出来的是float类型。
进制表示:
进制转换:
布尔类型转换:bool()
三个引号可以再IDLE下回车不会执行换行。print函数可以输出n这样的反义字符。
单个引号想回车换行可以再前面加上字符即可。
''' sadasdj adas ''' Out[1]: '\nsadasdj\nadas\n' 'asda File "<ipython-input-2-6af9d7d5e65d>", line 1 'asda ^ SyntaxError: EOL while scanning string literal 'asdd\ adsad\ sad' Out[3]: 'asddadsadsad' print('asda\nsada\n') asda sada ''' asda\n ''' Out[5]: '\nasda\n\n'
原始字符串在print时只是输出里面的字符,不考虑反义之类的,小心r大写R都没有关系。
print(r'c:\nsda\nsds') c:\nsda\nsds print(r'let's go') File "<ipython-input-3-a81b31c0c433>", line 1 print(r'let's go') ^ SyntaxError: invalid syntax
1.字符串的'+'和'*'
"hello"+"world" Out[1]: 'helloworld' "hello"*3 Out[2]: 'hellohellohello'
2.获取字符串里的字符
"hello world"[0] Out[3]: 'h' "hello world"[-1] Out[4]: 'd' # 包括左面但是不包括右面 "hello world"[0:4] Out[5]: 'hell' "hello world"[0:-1] Out[6]: 'hello worl' # 超出长度时会按字符串最大的长度进行截取 "hello world"[0:20] Out[7]: 'hello world' # 没有右边的值的时候,表示直接输出到末尾 "hello world"[6:] Out[8]: 'world' # 负数在冒号前面的时候 "hello world"[-4:] Out[9]: 'orld'
1.1 基本操作
1.1.1 基本选取(切片)
["新月打击","苍白之瀑","月之降临","月神冲刺"] Out[10]: ['新月打击', '苍白之瀑', '月之降临', '月神冲刺'] ["新月打击","苍白之瀑","月之降临","月神冲刺"][0] Out[11]: '新月打击' ["新月打击","苍白之瀑","月之降临","月神冲刺"][0:2] Out[12]: ['新月打击', '苍白之瀑'] ["新月打击","苍白之瀑","月之降临","月神冲刺"][-1:] Out[13]: ['月神冲刺'] a = [1,2,3,4,5,6,7,8] print(a[0:3]) print(a[0:len(a):2]) print(a[len(a):0:-2]) [1, 2, 3] [1, 3, 5, 7] [8, 6, 4, 2] #可以看到,切片操作很简单,第二个冒号后面的数字可以看作是步长。注意负数时的用法。
可以看到,当没有冒号的时候,单个选取出的是元素的类型。但是当有冒号的时候,选取出的是序列的类型。这里需要注意
1.1.2 列表的相加和乘法
["新月打击","苍白之瀑","月之降临","月神冲刺"]+['虚弱','点燃'] Out[14]: ['新月打击', '苍白之瀑', '月之降临', '月神冲刺', '虚弱', '点燃'] ['虚弱','点燃']*3 Out[15]: ['虚弱', '点燃', '虚弱', '点燃', '虚弱', '点燃']
1.1.3 判断元素是否存在
3 in [1,2,3,4] Out[21]: True 3 not in [1,2,3,4] Out[22]: False
1.1.4 计算长度,最大小值
len([1,2,3]) Out[23]: 3 len("hesadad") Out[24]: 7 max([1,2,3,4,5,6]) Out[25]: 6 min([1,2,3,4]) Out[26]: 1
1.1.5 append()
可以向列表中追加元素。
a = [1,2,3,4] a.append('5') Out[22]: [1, 2, 3, 4, '5']
type((1)) Out[16]: int type(('sd')) Out[17]: str type((1,2,3)) Out[18]: tuple
如果括号里有一个元素,默认为是一个运算,不会认为是元组的括号。如果要定义只有一个元素的元组的:
type((1,)) Out[19]: tuple # 括号里面什么都没有表示一个空元组 type(()) Out[20]: tuple
a = (1,2,3,[4,5]) a[3][1] = '2' print(a) (1, 2, 3, [4, '2'])
我们可以看到元组里的列表可以改变
{1,2,3,4,5,6} - {1,2} Out[1]: {3, 4, 5, 6} {1,2,3,4,5,6} & {1,2} Out[2]: {1, 2} {1,2,3,4,5,6} | {1,2,7} Out[3]: {1, 2, 3, 4, 5, 6, 7}
type({}) Out[8]: dict type(set()) Out[9]: set len(set()) Out[10]: 0
a = 1 b = a a = 3 print(b) 1 a = [1,2,3,4] b = a a[0] = '1' print(b) ['1', 2, 3, 4]
值类型:int str tuple(不可改变),在重新定义的时候,因为不可改变会生成一个新的对象,这个时候b仍然指向原对象,a指向了一个新对象
引用类型:list,set,dict(可以改变),在定义一个新对象的时候,会在原对象的基础上进行改变而不产生新对象,所以无论是a还是b都会指向已经改变的原对象,所以a和b的值都会变化。
a = 'hello' id(a) Out[15]: 1510080259608 a = a + 's' id(a) Out[17]: 1510081716832 a[0] = 's' Traceback (most recent call last): File "<ipython-input-18-02436d67df37>", line 1, in <module> a[0] = 's' TypeError: 'str' object does not support item assignmentid()是查询在计算机中的内存位置,我们可以看到发生了变化。所以a = a + 's'是可以的。但是对字符串的赋值操作,是不可以的,因为str是不可变的类型。
0 and 1 Out[1]: 0 1 and 2 Out[2]: 2 1 and 0 Out[3]: 0 1 or 2 Out[4]: 1 0 or 1 Out[5]: 1
由上面的例子我们可以看出and和or的逻辑判断规则和c++一致。空字符串,0等判断为空,在上面的笔记中有记载。
成员运算符表示一个元素是否在一个组里;成员运算符返回值类型是bool类型。在字典中,是判断key值。
a = 1 a in {1:'1'} Out[7]: True a = '1' a in {1:'1'} Out[9]: False
is, is not
身份运算符比较的是身份而不是值,简单来说就是内存地址。和关系运算符“==”不一样。
a = 1 b = 1 a is b Out[12]: True id(a) Out[13]: 1438837200 id(b) Out[14]: 1438837200 b = 1.0 a is b Out[16]: False id(b) Out[17]: 2197963106536 a ==b Out[18]: True a = {1,2,3} b = {2,1,3} a==b Out[21]: True a is b Out[22]: False c = (1,2,3) d = (2,1,3) c ==d Out[25]: False c is d Out[26]: False id(a) Out[27]: 2197907160424 id(b) Out[28]: 2197990760232
我们可以看到,在无序的set集合中,元素顺序不一样在内存中位置不同,虽然值相同但是身份仍然不一样。
&, |, ^, ~, <<, >>
以上都是把数字当作二进制进行运算。把数字按照二进制进行换算,以&举例,相同位1,不同为0。然后再把二进制数转换成数字原来的进制。eg: 2&3 == 2
python中一切都是对象,对象有三大特征,值(value), 身份(id), 类型(type)。判断变量的类型,可以使用isinstance()这个函数。
a = 'sds' isinstance(a,str) Out[30]: True isinstance(a,(str,int,float)) Out[31]: True isinstance(a,int) Out[32]: False
isinstance可以判断对象中的子类是否满足条件,所以比较好。
+ 单行注释:# 快捷键:ctrl + /
+ 多行注释:""" """ 快捷键:alt + shift + a
用来查看模块或者类内部的变量,包括系统内置变量。
import sys infos = dir(sys) print(infos) ['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding',......] # 可见打出了许多的变量,是sys模块内部的变量。下面的代码中也有应用,只不过没有参数。
if __name__ == '__main__': pass #来判断模块是否被当作入口文件被调用,如果被当做模块就不会打印if条件成立执行的语句,如果被当做入口文件才会执行
# 由父包引入子包或者同级别引入的情况 import module # 只能引入同一个包(不包括子包)里的模块。注意这里不能直接引入模块的变量。 import module as name # 使用的时候name.变量/函数等。 from packet import module # 可以父包里的子包引入模块。 from packet.module import module.变量/函数等 from module import * # 引入module内__all__指定的变量/函数等。 from module import module.变量1, module.变量2,...... # 引入多个变量可用逗号隔开
该文件,可以在导入一个包,或者导入包中的函数的时候,系统会首先执行该文件。
from packet import * # 这行代码会引入被引入包中__init__.py中__all__指定的模块。
a = 2 b = 1 infos = dir() print(infos) ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b'] # 上方除了'a','b'都是系统内置的变量。
下面介绍几个比较重要的内置变量,利用import一个模块的时候会执行该模块里面的内容的机制。对于入口文件和模块文件,内置变量的值有所不同。
''' this is a c3 doc ''' print("name: "+__name__) print("package: "+__package__) print("doc: "+__doc__) print("flie: "+__file__) import sub11.c3 PS D:\pycode\sub1> python c2.py name: sub11.c3 package: sub11 doc: this is a c3 doc flie: D:\pycode\sub1\sub11\c3.py # __doc__记录的是该模块的开头注释 # __name__记录该模块的名字 # __package__记录该模块属于的包 # __file__记录该模块的文件的绝对路径
如果一个.py文件被当做一个应用程序的入口:
①它的名称不再是本身的模块名称,而是被强制更改为__main__
②它不属于任何包
③file内置变量不会像普通模块一样显示绝对路径,它所显示的值也不是确定值,和执行命令所在目录有关
注:python入口文件和普通导入的模块文件是有差异的。
''' this is a c3 doc ''' print("name: "+__name__) print("package: "+ ( __package__ or "当前模块不属于任何包")) print("doc: "+__doc__) print("flie: "+__file__) name: __main__ package: 当前模块不属于任何包 doc: this is a c3 doc flie: c3.py # 该文件属于sub11包(有__init__.py这个文件),但是我们是直接执行的c3.py文件,可见此时如果在c3.py中打印内置变量,__name__被强制定位__main__,而且package上也不会显示出所属于的包,file路径也发生了变化。
导入机制:
python模块导入时的搜索路径:
from ... import...
中如果没有出现.模块名
,也是绝对导入。.
号。比如你单独运行某个模块,但是在这个模块里你用了相对导入,那么就会报错。但是你在外面引入这个模块的时候是不存在问题的。main.py
的位置有关,与main.py
同级的包就是该包下所有模块的顶级包。而对于入口文件来说不存在包的概念。注意:
sys.path
中会自动添加该工程中的目录,所以假设你在模块a中相对引入其他模块b,模块b所在的位置超过了你现在所运行的文件(入口文件)所在的位置,但是只要不超过当前的工程目录所在的位置,仍然可以进行相对导入。import sys sys.setrecursionlimit(10000) # 可以设置最大迭代10000次。不过理论上虽然设置这么多,但实际上仍然达不到允许迭代这么多次。
python函数返回多个值直接在return后面用逗号分隔要返回的值即可,返回结果是tuple元组类型。比较好的接收函数返回的多个值的方法不是用一个变量接收元组然后用序号访问它的元素,而是直接用多个值接收然后分别使用这些变量,如:
def damage(skill1, skill2) damage1 = skll1 * 3 damage2 = skill2 * 3 + 10 return damage1, damage2 skill1_damage, skill2_damage = damage(3, 6) print(skill1_danage, skill2_damage)
上面的接受参数的方式叫做序列解包。
d = 1, 2, 3 print(type(d)) a, b, c = d print(a, b, c) print('----------------') a = b = c = 1 print(a, b, c) <class 'tuple'> 1 2 3 ---------------- 1 1 1
因为是序列解包,所以可以不是元组,列表也是可以的。最后如果多个变量取同一个值,那么可以用上面的方法来进行赋值。
函数参数有:
def demo(*param): print(param) print(type(param)) demo(1,2,3,[4,5,6]) (1, 2, 3, [4, 5, 6]) <class 'tuple'> # 传入可变参数,会定义为元组。 def demo(*param): print(param) print(type(param)) a = 1,2,3 demo(a) demo(*a) ((1, 2, 3),) <class 'tuple'> (1, 2, 3) <class 'tuple'> # *可以解包。 def demo(**param): print(param) print(type(param)) demo(q='万能牌', w='切牌', e='占卜') {'q': '万能牌', 'w': '切牌', 'e': '占卜'} <class 'dict'> # 可见传进来以后是一个字典,很方便。这就是关键字可变参数。 def demo(**param): print(param) print(type(param)) for key,value in param.items(): print(key,':',value,end='|| ') demo(q='万能牌', w='切牌', e='占卜') {'q': '万能牌', 'w': '切牌', 'e': '占卜'} <class 'dict'> q : 万能牌|| w : 切牌|| e : 占卜|| # 传入字典时可以采用上面的方式取出键值和内容。 def demo(**param): print(param) print(type(param)) for key,value in param.items(): print(key,':',value,end='|| ') a = {'q':'万能牌', 'w':'切牌', 'e':'占卜'} demo(**a) {'q': '万能牌', 'w': '切牌', 'e': '占卜'} <class 'dict'> q : 万能牌|| w : 切牌|| e : 占卜|| # 和传入元组一样,解序列可以传入两个*。
def demo(param1,param2 = 2,*param3): print(param1) print(param2) print(param3) demo('a', 1,2,3) a 1 (2, 3) # 可见如果默认参数在可变参数之前,会发生错误,和预想的(1,2,3)赋值给param3有区别。 --------------------------------------------------------------------------- # 调整一下顺序可以得到想要的结果 def f1(name1, *args, name2='2', **kw): print(name1) print(name2) print(args) print(kw) f1('1','3','4',a='1',b='2') 1 2 ('3', '4') {'a': '1', 'b': '2'}
__init__(self)
:类名.__init__()
来执行构造函数。__init__()
中;实例变量是定义在___init__()
中的。换句话说,实例变量是对象的,类变量是类的,二者不能混淆。class Student(): name = 'Catherian' age = 0 high = 170 def __init__(self, name, age, high): self.name = name self.age = age high = high # 注意这里的身高没有用self.high来定义 def doHomework(self): print('doHomework') student1 = Student('呵呵哒', 18, 180) student2 = Student('ojbk', 16, 175) print(student1.name, student1.age, student1.high) print(student2.name, student2.age, student2.high) print(Student.name, Student.age, Student.high) print(student1.__dict__) print(Student.__dict__) 呵呵哒 18 170 ojbk 16 170 Catherian 0 170 # 这里打印出的才是类变量 # 可以看到,尽管我们在实例化student1,student2的时候传入了身高high这个数据,但是打印的时候我们发现输出的是类变量high,并不是实例变量。 {'name': '呵呵哒', 'age': 18} # __dict__对与对象,打印出的是对象的实例变量。可见里面并没有high。所以实例变量是用 self. 来定义的。类的__dict__是打印出对象里面的内容,包括数据成员和方法,下面即是 {'__module__': '__main__', 'name': 'Catherian', 'age': 0, 'high': 170, '__init__': <function Student.__init__ at 0x000001F06B70F9D8>, 'doHomework': <function Student.doHomework at 0x000001F06B70FA60>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
虽然我们在实例化对象时传入了数据,但是我们发现high是类变量不是实例变量,但是仍然sudent1.high打印出了变量,这是类变量而不是实例变量。这是因为,python中的查找机制:当查找实例变量不存在的时候,会继续向上查找类中相对应的类变量,如果子类中没有父类中有(出现继承)时,会查找到父类。所以我们打印出了类变量。
self.
给出的是实例变量。self.
的形式来进行调用。因为你传入的是形参.类名.类变量
和self.__class__.类变量
class Student sum = 0 @classmethod def student_sum(cls): pass # cls可以更换,函数上面是一个装饰器,表示了这是一个类方法。cls换成self或者其他任意的都是可以的,和实例方法中self可以任意替换别的字符是一样的。
对于类方法,调用类变量:cls.类变量
即可。所以cls代表的就是所属于的类。在调用类方法的时候,可以 Student.studen_sum
也可以通过对象来调用,即:student1.student_sum
。但是建议用类名来调用比较好。
class Student sum = 0 @staticmethod def add(x,y) pass
静态方法上同样要有装饰器来修饰,但是函数中不用显式的传入self或者cls,更像是一个普通的函数。在类方法和静态方法中都不能调用实例变量。一般不建议用静态方法,类方法更方便。
在python中,实际上没有什么是不能访问的。成员可见性更像是一种标志,一切全靠自觉。定义私有变量或者方法的时候,只需要在变量或者方法前面加上双下划线就代表了私有(注意不要同时在后面再加上双下划线)。
# 我们定义一个学生类 class Student(): name = 'Catherian' age = 0 __high = 170 def __init__(self, name, age): self.name = name self.age = age self.__score = 0 def __doHomework(self): print('doHomework') student1 = Student('呵呵哒', 18) print(student1.__score) Traceback (most recent call last): File "c1.py", line 15, in <module> print(student1.__score) AttributeError: 'Student' object has no attribute '__score' # 可以看到不能这样访问。 --------------------------------------------------------------------- # 如果我们再加上一句再执行: student1 = Student('呵呵哒', 18) student1.__score = -1 print(student1.__score) -1 # 我们发现竟然可以成功赋值并且访问的。这是因为 studen1.__score = -1 这个操作其实是又定义了一个新的实例变量。我们可以打印看一下 student1 = Student('okk', 18) student1.__score = -1 # print(student1.__score) print(student1.__dict__) {'name': 'okk', 'age': 18, '_Student__score': 0, '__score': -1} # 我们可以看到,我们再里面定义的__score变量被定义成了_Student__score变量,__score变量是我们根据Python动态特性新定义出的实例变量。所以要访问私有变量也很简单: print(student1._Student__score) 0 # 所以这个真的全靠自觉,python中没什么是不能访问的。
python中可以单继承也可以多继承。
类变量和实例变量
中说明的搜索规则进行。super(子类名, self)
进行调用父类重名函数。# 定义一个Human父类 class Human(): sum = 0 def __init__(self, name, age): self.name = name self.age = age self.__class__.sum += 1 def get_name(self): print(self.name) def do_Homework(self): # 重名的方法 print("this is a parent method") # 定义一个子类Student from c2 import Human class Student(Human): sum = 0 # 和父类重名的类变量 def __init__(self, name, age, score): # 父类还有两个参数,所以这里有三个参数 Human.__init__(self, name, age) # 这里注意通过类名调用方法,不能不加self self.score = score self.__class__.sum += 1 def do_Homework(self): # 和父类重名的方法。 super(Student, self).do_Homework() print('doHomework') student1 = Student('okk', 18, 61) print(student1.sum) print(Student.sum) print(student1.get_name()) print(student1.do_Homework()) 2 # 可见通过父类方法里对sum的操作,继承到子类中时,对于重名变量仍然可以操作子类中的重名变量。 2 # 根据搜索机制,实例变量里没有找到子类里的类变量,再没有找父类。 okk None this is a parent method # 可见调用了父类中的方法。 doHomework None
python中的枚举类型其实是一个类。
from enum import Enum class diamond(Enum): # 必须要继承父类Enum YELLOW = 1 BLUE = 2 GREEN = 3 RED = 4 print(diamond.YELLOW) diamond.YELLOW # 可见打印出的就是diamend.YELLOW
from enum import Enum class diamond(Enum): YELLOW = 1 BLUE = 1 GREEN = 3 RED = 4 print(diamond.BLUE) print(diamond.__members__.items()) # items()可以不需要。打印出所有的枚举类型。 diamond.YELLOW # 可打印的是BLUE出来的是YEELOW。 odict_items([('YELLOW', <diamond.YELLOW: 1>), ('BLUE', <diamond.YELLOW: 1>), ('GREEN', <diamond.GREEN: 3>), ('RED', <diamond.RED: 4>)])
diamond.YELLOW = 5
是会报错的。from enum import Enum class diamond(Enum): YELLOW = 1 BLUE = 2 GREEN = 3 RED = 4 print("枚举类型为:", type(diamond.GREEN), diamond.GREEN) print("枚举的名称为", type(diamond.GREEN.name), diamond.GREEN.name) print("枚举的值为:", diamond.GREEN.value) 枚举类型为: <enum 'diamond'> diamond.GREEN 枚举的名称为 <class 'str'> GREEN 枚举的值为: 3
for i in diamond: print(i) diamond.YELLOW diamond.BLUE diamond.GREEN diamond.RED
class diamond(Enum): YELLOW = 1 BLUE = 2 GREEN = 3 RED = 4 a = 1 print(diamond(a)) diamond.YELLOW # 从一个具体的值获得相应的枚举类型。很有用。
from enum import IntEnum
,在枚举类的括号里为IntEnum
。from enum import Enum from enum import IntEnum, unique @unique # 装饰器 class diamond(IntEnum): YELLOW = 1 BLUE = 2 GREEN = 3 RED = 4