首页 > 编程语言 > 详细

Python学习笔记——基础语法篇

时间:2020-04-08 11:33:58      阅读:58      评论:0      收藏:0      [点我收藏+]

一、Python初识(IDE环境及基本语法,Spyder快捷方式)

      Python是一种解释型、面向对象、动态数据类型的高级程序设计语言,没有编译过程,可移植,可嵌入,可扩展。

IDE

      1.检查Python版本:

       运行应用程序Terminal(win+R),输入cmd,进入界面后输入python,查看是否安装,未安装前往https://www.python.org/网址安装对应版本python。

      2.IDE集成环境

       (1)Anaconda spyder官网下载链接:https://www.anaconda.com/download/

百度云盘: Anaconda2 python2.7 链接:https://pan.baidu.com/s/1UNLhUlpW04y0AuZlglyQJA 密码:axd1

       (2)Pycharm:下载链接https://www.jetbrains.com/pycharm/download/    在安装完PyCharm后,还需要再安装python,否则在PyCharm的project interpreter中就没有可选项。Python (Windows环境配置),如下

           a.在环境变量path中添加Python目录:"我的电脑"右键点击“属性”,进入“高级系统设置”点击“环境变量”,找到PATH,添加“;%python安装路径”,保存即可。

           b.在命令提示框中(cmd) : 输入path=%path%;C:\Python,按下"Enter"。 注意:C:\Python 是Python的安装目录。

中文编码

       首行代码敲入# -*- coding: UTF-8 -*-或者#coding=utf-8才可以正确显示中文

spyder快捷方式:

  1. python -V           查看快捷方式
  2. Ctrl + 1               注释/反注释
  3. Ctrl + 4/5            块注释/块反注释
  4. Ctrl + L               跳转到行号
  5. F12                    断点设置 
  6. F5                      运行
  7. Ctrl + Y              反撤销       
  8. Ctrl + Z              反撤销   
  9. SHIFT + F12     条件断点
  10. Ctrl + Shift + W 关闭所有
  11. Ctrl +空格键      代码完成
  12. Tab/Shift + Tab  代码缩进/反缩进
  13. Ctrl +I               显示帮助
  14. python script.py 调用python脚本#!/usr/bin/python 被忽略,等同于注释。
  15. ./script.py           调用python脚本#!/usr/bin/python指定解释器的路径。
  16. reset 后得Once deleted...  输入y回车即可清除IPython变量。
  17. reset in/out         删除所有之前输入输入输出结果记录,同上操作。
  18. Ctrl+L                 清空IPython控制台的记录即可。
  19. clear                   清空控制台

代码格式

  1. 缩进:建议缩进适应四个空格,提高可读性。在程序中混合使用制表符和空格都可能导致难以解决的问题,可将文件中所有制表符转换为空格。注意:python对代码缩进要求十分严格,是一门非常优秀的语言,要配置好IDE的缩进。
  2. 行长: 建议每行不超过79字符。
  3. 空行:空行将程序的不同部分分开,组织程序文件。

二、Python变量和简单数据类型、列表、元组、字典、集合

变量

  1. 命名:不能包含空格,只能由字母、数字(不可作为开头)和下划线组成。
  2.  不要将Python关键字和函数名用作变量名,即不要使用Python保留字用于特殊用途的单词。
  3. 要简短且具有描述性,慎用小写字母l(像数字1)和大写字母O(像数字0)。

数据类型

  1. 整数执行加(+)减(-)乘(*)除(/)运算。注意:在Python2中,整数除法的结果只包含整数部分,小数部分直接被删除(没有四舍五入,直接删除),要避免这种情况,务必确保至少有一个操作数为浮点数,这样结果也将为浮点数。
  2. 字符串:用引号括起来的一系列字符。(引号可单可双,单不可含撇号)
  •         str.title()       以首字母大写的方式显示每个单词。
  •         str.upper()   全部大写
  •         str.lower()    全部小写
  •         str()              转字符串函数,避免类型错误
  •         +                   合并字符串
  •         str.rstrip()      删除字符串末尾空白
  •         str.lstrip()      删除字符串开头空白
  •         str.strip()       删除字符串两端空白

列表

由一系列按特定顺序排列的元素组成,用方括号([])来表示列表,并用逗号来分割其中的元素。

  1. 访问:列表名[下标],第一个列表元素下标为0,最后一个列表元素为-1。
  2. 修改:列表名[下标] = xxx。
  3. append(xxx),将元素xxx添加到列表末尾,而不影响列表中的其他所有元素。
  4. insert(num,xxx),将元素xxx插入列表第num个位置,剩下元素右移。
  5. del(num),删除第num个位置的元素,无法再使用。
  6. pop(),删除列表末尾的元素,并让你能够接着使用它,也可以使用pop()来删除列表中任何位置的元素,只需要在括号中指定要删除的元素的索引即可。
  7. remove(),可以从列表中删除元素,也可接着使用它的值。
  8. sort(),对列表进行永久性排序,若需按与字母顺序相反的顺序排列列表元素,向sort()方法传递参数reverse=True。
  9. reverse(),反转列表元素的排列顺序,可再次调用后恢复到原来的排列顺序。
  10. len(),列表的长度。
  11. for循环对列表的每个元素访问或者执行相同的操作。
  12. list(),方法range()生成一系列数字,创建数字列表时,可使用函数list()将range()结果直接转换为列表,若将range()作为函数list()的参数,输出将为一个数字列表。使用range()可指定步长,eg,range(2,11,2)从2开始数,然后不断地加2,直到达到或超过终值(11)。
  13. 列表统计函数:min(),max(),sum()。
  14. 对列表进行切片使用,可指定要使用的第一个元素的索引和最后一个元素的索引加1,负数索引可返回离列表末尾相应距离的元素。

元组

(,,,,)不能修改的值,不可变的列表成为元组,不能修改元组的元素,可以给存储元祖的变量赋值。任意无符号的对象,以逗号隔开,默认为元组。

  1. 元组[下标],访问。下标1开始,-1取最后。
  2. 元组+元组,连接操作。
  3. del 元组,删除整个元组,无法删除元组元素。
  4. len(),元组元素个数。还有min(),max()方法。
  5. 元组*n,将元组复制n次。
  6. for x in 元组:,迭代。
  7. cmp(),比较两个元组元素。
  8. tuple(),将列表转为元组。

字典

字典式一系列键-值对{key:value,key:value,……},每个键都与一个值相关,使用键来访问与值相关联的值,与键相关联的值可以是数字、字符串、列表乃至字典。

  1. 字典名[‘键名‘],进行访问。
  2. 字典名[‘键名‘] = xxx,添加或修改键对值。
  3. 字典名 = {},创建控字典。
  4. del 字典名[‘键对值‘],删除字典中键对值。
  5. for 键,值 in 字典.items():,返回一个键-值对列表。即便遍历字典时,键-值对的返回顺序也与存储顺序不同。Python不关心键-值对的存储顺序,而只跟踪键和值之间的关系。
  6. keys(),此方法并不是只能用于遍历,它返回一个列表,其中包含字典中的所有键。按顺序遍历字典中的所有键:对方法keys()的结果调用函数sorted()。
  7. values(),遍历字典中的所有值,返回一个值列表,而不包含任何键。通过对包含重复元素的列表调用set(),可让Python找到列表中独一无二的元素,并使用这些元素来创建一个集合。
  8. 嵌套:将一系列字典存储在列表中,或将列表作为值存储在字典中。字典列表型:多个字典放在一个列表;在字典中存储列表:在字典中将一个键关联到多个值时 ,都可以在字典中嵌套一个列表;在字典中存储字典:嵌套的字典结构希望都相同时。

集合

{...,...,...},一个无序的不重复元素序列,创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

  1. add()/update(),添加元素,参数可以是列表,元组,字典等,自动合并重复。
  2. remove(xxx),将xxx元素从集合中移除。
  3. len(),集合元素个数。
  4. clear(),清除集合。
  5. xxx in 集合,判断xxx是否存在于集合中。
  6. union(),两个集合的并集。
  7. pop(),随机移除集合元素。
  8. intersection()/intersection_update(),集合交集。
  9. difference(),集合差集。
  10. difference——update(),移除集合中的元素,该元素在指定的集合也存在。

三、if语句、for和while循环(python无switch语句)

if语句

if语句的核心都是一个值为True或False的表达式。如果条件测试的值为True,Python就执行紧跟在if语句后面的代码;如果为False,Python就忽略这些代码。

1 if condition1:
2     statement1……
3 elif condition2:
4     statement2……
5 elif condition3:
6     statement3……
7 else:
8     statement4……
技术分享图片
  1. ==,检查值是否相等(检查是否相等时不考虑大小写)。
  2. !=,检查是否不相等。
  3. <、>、≥、≤,比较数字。
  4. and,检查多个条件。
  5. in,检查特定值是否(不)包含在列表中。
  6. 布尔表达式(True/False)。
  7. 简单:一个测试一个操作。
  8. #if-else语句:else指定条件测试未通过时要执行的操作。
  9. #if-elif-else结构:依次检查每个条件测试,指导遇到通过了的条件测试,执行紧跟的代码,并跳过余下的测试。
  10. #使用多个elif代码块也可省略else代码块。
  11. is 用来判断是否指向相同。

for循环

对列表中的每个元素都执行相同的操作,编写是,对于用于存储列表中每个值得临时变量,可指定任何名称。

1 for sth in sth:
2      sth
技术分享图片

while循环

使用while sth循环进行数数或者条件测试,不断运行直到条件不满足或者终止。

技术分享图片
while condition:
    statements……
  1. 标志:定义一个变量,用于判断整个程序是否处于活动状态。
  2. 使用break退出循环。
  3. 在循环中使用continue:要返回到循环开头,并根据条件测试结果决定是否继续执行循环。
  4. 避免无限循环:Ctrl+C,也可关闭显示程序输出的终端窗口。
  5. pass 不做任何事情,一般用做占位语句。

python没有switch语句,一般用if...elif...else语句替换

四、函数、异常处理

函数

带名字的代码块。def name:定义一个函数name,定义以冒号结尾。

  1. 三引号括起的文档字符串,Python用它来生成有关程序中函数的文档。
  2. 匿名函数lambda [arg1[,arg2,...,argn]]:expression,不能访问自有参数列表之外或全局命名空间里的参数。
  3. 全局变量(定义在函数外,可以在整个程序范围内访问)与局部变量(定义在函数内部的变量,只能在其被声明的函数内部访问)。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
  4. 向函数传递信息:
  • 实参——调用函数是传递给函数的信息。
  • 形参——函数完成其工作所需的一项信息。
  • 位置实参——要求实参的顺序与形参的顺序相同(因为调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参)。
  • 关键字实参——传递给函数的名称——值对,在实参中将名称和值关联起来了,无需考虑函数调用中的实参顺序,清楚地指明了函数调用中各个值得用途。
  • 默认值——给每个形参指定默认值,在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值。
  • return [表达式]——返回值语句将值(任何类型的值,包括列表和字典等较复杂的数据结构。)返回到调用函数的代码行。
  • 传递列表时,若要禁止函数修改列表,可函数传递列表的副本而不是原件,list_name[:]。
  • 传递任意数量的实参:函数使用一个形参*toppings,不管调用语句提供了多少实参,这个形参都将它们统统收入囊中。
  • import——可将函数存储在模块的独立文件中,用import导入到主程序,import允许在当前运行的程序文件中使用模块中的代码,使用as sth给模块指定别名。也可使用from sth import sth,导入模块中的特定函数,使用as sth给函数指定别名。from sth import *导入模块中的所有函数。所有的import语句都应放在文件开头,除非在文件开头使用了注释来描述整个程序。

异常

异常:即一个事件的发生,该事件将会在程序执行过程中发生,影响程序的正常执行。

  1. 处理方式:try...except...else,try后的语句执行时发生异常,跳回try并执行第一个匹配该异常的except子句,异常处理完毕后通过整个try语句,执行else语句后的语句,finally语句是不论有无异常都将执行。
  2. 触发异常:raise[Exception[,args[,traceback]]],也可以触发用户自定义的异常。

五、用户输入、文件

用户输入

  1. input(“sth”),获取用户输入字符串,即让程序暂停运行,等待用户输入一些文本,获取后,可以将其存储在一个变量中,以方便使用。可将该提示存储在一个变量中,再将该变量传递给函数input()。
  2. 函数int()可将用户输入的数字字符串转换为数值表示。
  3. 求模运算符(%)将两个数相除并返回余数,不会指出一个数是另一个数的多少倍,而只指出余数是多少。
  4. raw_input([prompt]) ,函数从标准输入读取一个行,并返回一个字符串(去掉结尾的换行符)。
  5. print(‘‘),标准输出打印。

文件

  • open(),读取整个文件数据,返回一个表示文件的对象。函数接受一个参数:要打开的文件的名称。Python在当前执行的文件所在的目录中查找指定的文件。指定一个变量将这个对象存储。
  • 关键字with,在不需要访问文件后将其关闭。也可以调用open()和close()来打开和关闭文件。但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。未妥善地关闭文件可能会导致数据丢失或受损。如果在程序中过早地调用close(),会发现需要使用文件时它已关闭。所以让Python去确定:只管打开文件,并在需要时使用它,Python自会在合适的时候自动将其关闭。
  • 方法read(),读取这个文件的全部内容,并将其作为一个长长的字符串存储,read()到达文件末尾时返回一个空字符串,而这个空字符串显示出来时就是一个空行。要删除末尾的空行,可使用rstrip()。
  • 在Windows系统中,在文件路径中使用反斜杠(\)而不是斜杠(/),将绝对文件路径(将文件在计算机中的准确位置)。为确保在Windows中万无一失,应以原始字符串的方式指定路径,即在开头的单引号前加上r
  • 要以每次一行的方式读取文件,可对文件对象使用for循环。消除空白行使用rstrip()。
  • 创建一个包含文件各行内容的列表:readlines()从文件中读取每一行,并将其存储在一个列表中。
  • 读取文本文件时将其中的所有文本都解读为字符串。如果读取的是数字,并要将其作为数值使用,就必须使用函数int()将其转换为整数,或使用float()将其转换为浮点数。

  • 调用open()时提供了两个实参,第一个实参也是要打开的文件的名称;第二个实参(’w’)告诉Python,要以写入模式打开这个文件。打开文件时,可指定读取模式(’r’)、写入模式(’w’)、附加模式(’a’)——给文件添加内容而不是覆盖原有的内容和读取和写入文件的模式(’r+’),若省略了模式实参,Python将以默认的只读模式打开文件。
  • Python只能将字符串写入文本文件,要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
  • 写入多行,函数write()不会在你写入的文本末尾添加换行符,要让每个字符串都单独占一行,需要在write()语句中包含换行符
  • split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
  • 使用模块json来存储数据,能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。JSON(JavaScript Object Notation),json.dump接受两个实参:要存储的数据以及可用于存储数据的文件对象。使用json.load()加载存储在xxx.json中,并将其存储到变量xxx中。
  • 将代码划分为一系列完成具体工作的函数,称为重构。
  • 创建、删除、更改目录:os.mkdir("newdir")——在当前目录下创建新的目录;os.chdir("newdir")——改变当前目录;od.getcwd()获取当前目录;os.rmdir("dirname")——删除目录,删除之前,该目录下的所有内容应该被删除。

六、面向对象

类:用来描述具有相同的属性和方法的对象的集合。

对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

基本概念

  1. 实例化:根据类来创建对象,可按需求根据类创建任意数量的实例。
  2. 在Python中,类——首字母大写的驼峰命名法且定义括号为控,实例——小写的名称,在类中可用一个空行来分隔方法,在模块中,使用两个空行来分隔类。
  3. 类中的函数称为方法;_init_()是一个特殊的方法,每当你根据类创建新实例时,Python都会自动运行,在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面,因为调用这个方法来创建实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
  4. 访问属性与调用方法:句点表示法。eg.dog.name,dog.sit()
  5. 类中的每个属性都必须有初始值,哪怕这个值是0或字符串,但设置默认值时,在方法_init_()内指定这种初始值是可行的,如果对某个属性这样做了,就无需包含为它提供初始值的形参。
  6. 内置属性:__dict__(类的属性,有类的数据属性组成),__doc__(类的文档字符串),__name__(类名),__module__(类定义所在的模块),__bases__(类的所有父类构成元素,包含一个由所有父类组成的元素)。
  7. 销毁(垃圾回收):对象一旦被创建就创建一个引用计数器,这个引用计数变为0时,适当时候被回收。__del__析构函数在对象销毁时调用。

    垃圾回收
    1.小整数[-5,256)对象池将整数对象提前创建好,位于该区间的对象不会被回收。但定义2个相同的字符串时,引用计数为0,触发垃圾回收。
    2.每一个大整数,均创建一个对象。
    3.单个单词,不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁。

    GC垃圾回收——发现并处理不可达的垃圾对象
    垃圾回收 = 垃圾检查+垃圾回收
     import gc后is_enable() = True启动自动垃圾回收。
    常用函数:
    1.gc.set_debug(flags)设置gc的debug日志,一般设置为gc.DEBUG_LEAK
    2.gc.collect(generation)显式进行垃圾回收,可以输入参数,0代表只检查第一代的对象,1代表检查一,二代的对象,2代表检查一,二,三代的对象,如果不传参数,执行一个full collection,也就是等于传2,返回不可达对象的数目
    3.gc.gwt_threshold()获取的gc模块中自动执行垃圾回收的频率。
    4.gc.set_threshold(threshold0[,threshold1,[,threshold2]])设置自动执行垃圾回收频率。
    5.gc.get_count()获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表。
    引用计数机制(由于解决不了循环引用问题)为主,分代收集两种机制为辅的策略。
    分代:对象在创建的时候,放在一代中,如果在一次一代的垃圾检查中,该对象存活下来,放到第二代,同理,二代进入三代。
    1.引用计数+1:对象被创建;对象被引用;对象被当作参数传入到一个函数中;对象作为一个元素,存储在容器中。
    2.引用计数-1:对象的别名被显示销毁;对象的别名被赋予新的对象;一个对象离开它的作用域;对象所在的容器被销毁,或从容器中删除对象。
    3.查看一个对象的引用计数:sys.getrefcount(xxx)

  8. 重写:父类方法的功能不满足需求,可在子类重写父类的方法。__init__(self[,args])、__del__(self)、__repr__(self)、__str__(self)、__cmp__(self,x)。
  9. __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *。__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
  10. 类属性与方法:
    ***xx:公有变量
    ***_x:单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问。
    ***__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问。
    ***__xx__:双前后下划线,用户名字空间的魔法对象或属性。
    ***xx_:单后置下划线,用于避免与Python关键词的冲突。 
    ***通过 name mangling(名字重整)如:_Class__object机制就可以访问private了。
    属性property
           1.私有属性添加getter和setter方法
           2.使用property升级setter和getter方法,相当于把方法进行了封装,开发者在对属性设置数据的时候更方便。
           3.直接在第一个get类方法前面@property,再在set方法前面@get类方法名的属性setter方法。
  11. 传递对象:可更改(mutable):list、dict和不可更改(immutable):strings、tuples、numbers。
  12. 继承
  • 一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。不允许实例化的类访问私有数据,但可以使用 object._className__attrName( 对象名._类名__私有属性名 )访问属性。
  • 创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值,子类的_init_()需要父类施以援手。
  • 定义子类时,必须在括号内指定父类的名称。
  • super()是一个特殊函数,帮助Python将父类和子类关联起来,父类也称为超类(superclass)。
  • 让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
  • 可将类的一部分作为一个独立的类提取出来,将大型类拆分成多个协同工作的小类。

核心编程

1.迭代器:迭代访问集合元素并记住遍历位置的对象,只前不退。

1)可迭代的对象(可直接作用于for循环的对象)
一类是集合数据类型:int、tuple、dict、set、str等。
二是generator,包括生成器和带yield的generator function。
2)使用collections模块的Iterable对象放在isinstance(对象,Iterable)中,判断一个对象是否是Iterator对象。
3)迭代器:可以被next()函数调用并不断返回下一个值的对象。
4)iter()函数,生成器都是Iterator对向,但list、dict、str可迭代,但不是Iterator。用iter()函数可以将其变为Iterator。

2.闭包:有权访问另一个函数作用域中变量的函数。
1)函数引用
2)函数内部在定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称为闭包。

3.装饰器:本身是一个函数,目的是在不改变待装饰函数代码的情况下,增加额外的功能,装饰新的返回值是已装饰的函数对象。
1)@函数名表示,一定会执行装饰,不是等到调用时才装饰。装饰先装饰最里层即代码最后的装饰器先装,调用则相反。
2)有参数的函数装饰要注意装饰器内部定义的方法必须带有同样数量的形参。多参使用(*args, **kwargs)接收。
3)有返回值的函数装饰要在装饰函数调用中用接收值返回。 
4)带有参数的装饰器,能够在运行时有不同的功能。

4.python动态添加属性和方法
1)使用types.MethodType(method, type)绑定后赋值给属性再调用该属性方法即可。
2)静态方法或者类方法直接赋值给对象属性即可调用无需绑定。
3)对属性采用__slots__定义,实例只能对这些属性进行赋值,不能对其他属性赋值。但只对当前类实例起作用,对集成的子类是不起作用的。

5.生成器:一边循环一边计算的机制——generator
1)生成方式:将列表生成方式的[]改为()。
2)在函数中用yield语句可以将函数变为生成器。将该函数变为生成器对象后进行迭代取出。
3)可以使用next(xx)方法或者xx.__next__()获取值,只要yield语句不重新调用其值就不会改变。
4)xx.send(some)发送值作为yield的值(但是必须是生成器已经启动的情况下)。

6.类装饰器:把类当成装饰器放在函数前进行装饰。装饰时调用类的__init__方法,装饰完的函数被调用时调用类的__call__方法。

元类(魔法,较难用到):
1.class创建的类也是一个对象,可以在运行时动态的创建它们,就像其他任何对象一样。
2.type(“类名”,由父类名称组成的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
3.使用xxx.__class__可以查看创建者。
4.定义类时添加__metaclass__属性,就选定了系统创建该类的元类。

7.常用的标准库
builtins 内建函数默认加载
os 操作系统接口
sys Python自身的运行环境
functools 常用的工具
json 编码和解码JSON对象
logging 记录日志和调试
multiprocessing 多进程
threading 多进程
copy 拷贝
time 时间
datetime 时间和日期
calendar 日历
hashlib 加密算法
random 生成随机数
re 字符串正则匹配
socket 标准的BSD Socket API
shutil 文件和目录管理
glob 基于文件通配符搜索

Python学习笔记——基础语法篇

原文:https://www.cnblogs.com/caoer/p/12658477.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!