Linux运维部落 |国内最专业的Linux万达登录,万达娱乐登录 Fri, 24 Nov 2017 12:06:38 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.9 用户,管理,权限 /88845 /88845#respond Fri, 24 Nov 2017 12:06:38 +0000 /88845 /88845/feed 0 用户,管理,权限 /88844 /88844#respond Fri, 24 Nov 2017 12:04:28 +0000 /88844 /88844/feed 0 第九周shell脚本编程练习 /88838 /88838#respond Thu, 23 Nov 2017 13:43:34 +0000 /88838 1、写一个脚本,判断当前系统上所有用户的shell是否为可登录shell(即用户的shell不是/sbin/nologin);分别这两类用户的个数;通过字符串比较来实现;

9.1

2、写一个脚本

(1)获取当前主机的主机名,保存于hostname变量中;

(2)判断此变量的值是否为localhost,如果是,则将当前主机名修改www.magedu.com;

(3)否则,则显示当前主机名;

9.2

3、写一个脚本,完成如下功能

(1)传递一个磁盘设备文件路径给脚本,判断此设备是否存在;

(2)如果存在,则显示此设备上的所有分区信息;

9.3

4、写一个脚本,完成如下功能

脚本能够接受一个参数;

(1)如果参数1为quit,则显示退出脚本,并执行正常退出;

(2)如果参数1为yes,则显示继续执行脚本;

(3)否则,参数1为其它任意值,均执行非正常退出;

9.4

5、写一个脚本,完成如下功能

传递一个参数给脚本,此参数为gzip、bzip2或者xz三者之一;

(1)如果参数1的值为gzip,则使用tar和gzip归档压缩/etc目录至/backups目录中,并命名为/backups/etc-20160613.tar.gz;

(2)如果参数1的值为bzip2,则使用tar和bzip2归档压缩/etc目录至/backups目录中,并命名为/backups/etc-20160613.tar.bz2;

(3)如果参数1的值为xz,则使用tar和xz归档压缩/etc目录至/backups目录中,并命名为/backups/etc-20160613.tar.xz;

(4)其它任意值,则显示错误压缩工具,并执行非正常退出;

9.5

6、写一个脚本,接受一个路径参数:

(1)如果为普通文件,则说明其可被正常访问;

(2)如果是目录文件,则说明可对其使用cd命令;

(3)如果为符号链接文件,则说明是个访问路径;

(4)其它为无法判断;

9.6

7、写一个脚本,取得当前主机的主机名,判断

(1)如果主机名为空或为localhost,或为”(none)”,则将其命名为mail.magedu.com;

9.7

]]>
/88838/feed 0
使用groupmems -l -g 组名选项遇到的问题 /88830 /88830#respond Thu, 23 Nov 2017 12:45:06 +0000 /88830 groupmems -l选项帮助文档上写的意思是显示的是一次组为附加组的用户列表,但是这是不准确的

那么先创建几个用户吧

[root@centos7 ~]#useradd zhao
[root@centos7 ~]#useradd li
[root@centos7 ~]#useradd zhang
[root@centos7 ~]#getent shadow zhao zhang li
zhao:!!:17493:0:99999:7:::
zhang:!!:17493:0:99999:7:::
li:!!:17493:0:99999:7:::

首先先将zhang用户设为zhang组的组管理员

[root@centos7 ~]#gpasswd -A zhang zhang
[root@centos7 ~]#getent gshadow zhang
zhang:!:zhang:

用zhang用户管理组,将zhao用户添加到zhang组

[root@centos7 ~]#su – zhang
[zhang@centos7 ~]$gpasswd -a zhao -g zhang
Adding user zhao to group zhang

但是我们用zhang能不能查看组成员呢?

[zhang@centos7 ~]$getent gshadow zhang

结果组管理员却不能查看,那么还是用root用户查看吧

[root@centos7 ~]#getent gshadow zhang
zhang:!:zhang:zhao
[root@centos7 ~]#getent group zhang
zhang:x:1007:zhao
[root@centos7 ~]#id zhao
uid=1002(zhao) gid=1002(zhao) groups=1002(zhao),1007(zhang)

使用groupmems查看

[root@centos7 ~]#groupmems -l -g zhang
zhao

从上面的结果来看zhang组是zhao的附加组,我们可以暂时理解为gshadow和group文件最后一个字段是以此组作为附加组的成员列表,那么现在做一个合理的实验,为了方便操作我不在切换成zhang用户管理该组了,现在将zhang用户添加到zhang组里:

[root@centos7 ~]#gpasswd -a zhang zhang
Adding user zhang to group zhang
[root@centos7 ~]#getent gshadow zhang
zhang:!:zhang:zhao,zhang
[root@centos7 ~]#getent group zhang
zhang:x:1007:zhao,zhang
[root@centos7 ~]#id zhang
uid=1004(zhang) gid=1007(zhang) groups=1007(zhang)

从上面的结果来看,zhang用户的确被添加到zhang组里了,但是zhang组仍然是zhang用户的主组,我们用groupmems查看一下

[root@centos7 ~]#groupmems -l -g zhang
zhao zhang

从上面的执行结果来看zhang组是zhang的主组却也用groupmems -l选项显示出来了,这就说明groupmems这个命令查看的就不是以此组作为附加组的成员列表了

深究一下,先查看与组有关的文件

[root@centos7 ~]#getent gshadow zhang
zhang:!:zhang:zhao,zhang
[root@centos7 ~]#getent group zhang
zhang:x:1007:zhao,zhang

貌似跟着两个文件都有关呢,那么修改一下gshadow文件在zhang组最后一个字段的后面添加一个用户li(其实可以不是用户,随便的字符串都行),在group文件在zhang组最后一个字段的后面添加一个不存在的用户wangcai

[root@centos7 ~]#getent gshadow zhang
zhang:!:zhang:zhao,zhang,li
[root@centos7 ~]#getent group zhang
zhang:x:1007:zhao,zhang,wangcai

添加好后,在执行groupmems -l命令查看结果:

[root@centos7 ~]#groupmems -l -g zhang
zhao zhang wangcai

结果很明显了,groupmems -l显示的并不一定是以此组为附加组的用户列表,该命令是读取的/etc/group文件中对应组的最后一个字段的全部内容。

]]>
/88830/feed 0
20171123 Shell编程 /88829 /88829#respond Thu, 23 Nov 2017 10:59:13 +0000 /88829 一、shell编程

shell编程就是对一堆Linux命令的逻辑化处理

1. 变量

(1) 定义变量,类如:name=”zhao” ,”=”两边不用空格隔开,后面的变量需要使用” “,否则会 有可能出现错误;

shell2

可以使用echo 来显示变量的值:echo $变量名,类如:

s1

(2)可以使用$来引用系统中已经存在的变量、常量,类如显示$ PS1:

s2

(3)可以使用命令来当变量,是一种命令调用命令的形式:

s3

(4)同样的也可以使用文章当作变量

s4

(5)unset 是用来删除变量的,unset 变量名 ,类如unset $name:

s5

(6)进程的相关知识:

用pstree可以查看当前的进程树

用echo $$可以查看当前的进程数

(7)

局部变量:生效的范围为当前的进程,对其他进程包括当前进程的子进程都无效

s6

环境变量(全局变量):生效范围为当前进程及其子进程都有效

环境变量的定义有两种:(1)使用export name=VALUE

(2)使用declare -x name=VALUE

export name=”zhao”

declare -x name=”lg”

s7

s8

(8)set 查看系统中所有的变量,函数,用export,declare和env查看系统中的环境变量

(9)只读模式(常量)只能声明,但不能修改,其的定义,有两种:

(1)readonly name=“VALUE”

(2)declare -r name=“VALUE”

s9

使用readonly -p 查看只读模式

(10)注意点() sh

2.shell编程

(1)使用程序来查看环境变量:

#!/bin/bash
n=son
echo “p.sh:name=$n” echo “son=$n”
son.sh

(2)编写脚本/root/bin/systminfo.sh,显示出当前主机系统信息:

#!/bin/bash
echo “The informations :
the hostname is:`hostname`
the IPv4 is:`ifconfig ens33|grep -o “[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}. [0-9]\{1,3\}”|head -n1`
the system release is:`cat \/etc\/centos-release`
the banben is :`uname -r`
the CPU is :`lscpu|grep “Model name”|cut -d: -f2`
the neicun is :
`df -h |grep “/dev/sda*”`

(3)编写脚本/root/bin/backup.sh,可实现每天将/etc/目录下备份到/root/etcYYYY-mm-dd中:

sh2

(4)编写脚本/root/bin/disk.sh,显示当前硬盘分区 中空间利用率最大的值:

#!/bin/bash
df -h |grep sda*|tr -s ” “|cut -d ” ” -f5|sort -n|tail -n1

(5)退出状态值

0代表成功,1-255代表失败,也可以通过exit[n]来自己设定值

使用$?来保存最近的命令退出状态

(6)位置 变量:在脚本的代码中调用命令行传递给脚本的参数

$1代表第一个参数,$2代表第二个参数,$n代表第n个参数

$0:命令本身 , $*代表传递给脚本的所有命令

$@:传递给脚本的所有参数,每个参数是一个独立的参数

set清空所有的变量

sh3

(7)新建文件,自动添加文件介绍等内容:

#!/bin/bash
date=`date +%F`
echo “#Filename: $1”
echo “#Revision: 1.0”
echo “#Language: bash shell”
echo “#Author : $2”
echo “#Date : $date”
touch $1
chmod +x $1
vim $1 +

4. bash中的算数运算:

(1)bash中支持:+,-,*,/,% ,**等运算

(2)let var=表达式

sh4

(3)$[ 表达式]

sh5

(4)$((表达式))

sh6

(5)expr 是一个命令,所以参数之间需要分开

sh7

(6)echo “算数表达式”| bc

sh8

(7)自增自减

++ — += -+

sh9

 

 

 

]]>
/88829/feed 0
踩踩Linux命令中的那些坑 /88818 /88818#respond Thu, 23 Nov 2017 05:38:22 +0000 /88818 expr的坑

expr 是用来对数值进行计算的命令,命令的前后参数需要用空格隔开

[root@localhost ~]# whatis expr
expr (1) – evaluate expressions 表达式求值

expr命令被用做表达式求职计算,但是 expr计算的结果为0的时候,将会被认为是错误的,不能作为条件判断的依据

例如:

[root@localhost ~]# expr 1 + 2

3

expr还可以对变量的值进行计算

[root@localhost ~]# n=3;expr $n + 2

5

但命令执行后是否成功呢??

$? 是shell中显示命令执行结果是否正确的内置变量,如果执行结果的值为0,表示命令正确执行

使用一个未定义的变量试试

[root@localhost ~]# expr $x + 2;echo $?

2

0

坑!

#结果是对的

[root@localhost ~]# expr $y + 0

0

#被判定为命令执行失败

[root@localhost ~]# echo $?

1

[root@localhost ~]# y=10;expr $y + 0

10

[root@localhost ~]# echo $?

0

原因

expr的执行结果如果是0,将会被 $? 认为命令执行失败。expr不能轻易用于作为条件判断,有时候不能当做条件判断的依据

在expr命令的帮助文档中有一句描述:Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0, 2 ifEXPRESSION is syntactically invalid, and 3 if an error occurred.

也就是说,如果表达式的执行结果为null或者0,就认为执行的最终结果为1[命令执行失败],否则为0[命令执行成功]

类似的情况

let的坑

[root@localhost ~]# i=0;let i++;echo $?

1

[root@localhost ~]# i=0;let ++i;echo $?

0

[root@localhost ~]# let m=0;echo $?

1

查一下let的帮助

help let

和expr类似的情况

Exit Status:If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.

[root@localhost ~]# i=10;j=-10;

[root@localhost ~]# let sum=i+j

执行结果是对的,但被判定为执行命令失败

[root@localhost ~]# echo $sum

0

[root@localhost ~]# echo $?

1

 

例如想计算出两个数的值就输出,则会出现不能成功输出计算得出值得情况,就是因为前一条命令被判定为执行失败,使用短路与的命令,后续不执行导致的,所以,只能把一条命令拆成2条命令去写

[root@localhost ~]# let sum=i+j && echo $sum

[root@localhost ~]# let sum=i+j ;echo $sum

0

用于条件判断的命令如果不严谨,将会导致一些无法预料的事情发生!

 

在做变量测试时候遇到的另一个坑

test命令

  • 长格式的例子:

test “$A” == “$B” && echo “Strings are equal”

test “$A” -eq“$B” && echo “Integers are equal”

  • 简写格式的例子:

[ “$A” == “$B” ] && echo “Strings are equal”

[ “$A” -eq “$B” ] && echo “Integers are equal”

[root@localhost ~]# whatis test

test (1) – check file types and compare values 检查文件类型和值进行比较

[root@localhost ~]# help test

test: test [expr]

Evaluate conditional expression.

其中有一个参数

-n STRING
STRING True if string is not empty. 如果字符串不为空表示为真

 

test的坑

测试成功返回0.测试失败返回255以内的数

[$name 是一个不存在的变量]

[root@localhost ~]# [ -n $name ] 为空的变量测试为真???what??

[root@localhost ~]# echo $?

0 竟然 测试成功

[root@localhost ~]# echo $name $name没有值

 

[root@localhost ~]# name=wang 给$name 赋值

[root@localhost ~]# [ -n $name ] 测试[如果变量不为空则为true]

[root@localhost ~]# echo $?

0 OK,没问题

[root@localhost ~]# unset name 删除$name变量,此时$name的值为空,测试时应该表现为假才对

[root@localhost ~]# [ -n $name ] ???不对了

[root@localhost ~]# echo $?

0 删除变量$name后,此时测试应该表现为失败,返回其他数字

[root@localhost ~]# test -n $name;echo $?

0

[root@localhost ~]# [[ -n $name ]]

[root@localhost ~]# echo $?

1

[root@localhost ~]# echo $name

#由于之前已经删掉了$name变量的值,所以已经为空,不为空表示为真,为空表现为假,所以一下的测试都是失败的

[root@localhost ~]# [ -n “$name”] 加上双引号进行测试

[root@localhost ~]# echo $?

1 由于已经unset掉了$name,所以测试的语句的返回值是其他数,这里是对的

[root@localhost ~]# test -n “$name” 加上引号测试变量

[root@localhost ~]# echo $?

1 由于已经unset掉了$name,所以测试的语句的返回值是其他数,这里是对的

 

不加引号,判断出来全是真,这是一个坑!坑!坑!

 

 

]]>
/88818/feed 0
python面向对象第二周魔术方法详解 /88806 /88806#respond Wed, 22 Nov 2017 03:03:25 +0000 /88806 魔法方法及其使用
__开头和结束的方法,定义外部没有办法直接调用,但会有影响使用
运算符号的魔法方法, + ,-,*,/,%,//,**, __add__,__sub__,__mul__,__truediv__,__mod__,__floordiv__,__pow__,
__divmod__(?),
系统内部对于数值型,字符串型,容器内型都定义了其中部分或者全部的运算符使用要求和办法,
我们在类中定义这些魔法方法,可以使得它们按照需要对对象类型进行运算符运算, 仍需要满足一些基本的概念
比如加减乘除都是在两个对象而言的,所以形参数量要为二 ,且其中一个为self(类自身的对象)其他大部分的运算符魔法方法对于参数数量和类型也有类似要求,
其他变种运算符 +=,-=,*=,/=,%=,//=,**= ,它们的魔法方法写法就是相应的名称前加一个i,它们对于形参数和类型也与前面的类似
判断运算符 <,<=,==,>,>=,!=
和运算符号的一样,他么的返,定义一般要求两个参数,且其中一个为self(类自身的对象),它们不一定要求返回布尔型的值,可以没有或者返回其他类型的值
在使用这些运算符对系统数据类型使用这些符号时不会有覆盖,或者不能使用的问题,因为他们内部的类中有魔法方法定义使用这些符号的使用规则,即使我们在自定义的类中对基本数据类型时使用运算符,依然能够准确表达含义

容器相关方法:__len__,__iter__,__contains__,__getitem__,__setitem__,__missing__
获取长度,迭代器, in运算符,索引访问,索引设置,其它
容器相关方法,在基本数据类型中的容器类型,list,tuple,set,dict中有实现其中大部分或全部方法,
对他们调用 len( ),可以使用是因为实现了__len__的魔法方法,在类中可以定义它,使得我们也可以在外部调用该方法,这个方法要求只有一个形参,且为类的对象,要有返回值且为整型,使用 len(对象)会调用这个方法
当迭代一个对象(使用for in 遍历)时会调用__iter__的方法,获取该方法返回的迭代器,for in 遍历的实质是遍历这个迭代器,所以这个对象可以被成为可迭代对象,任何数据类型如果实现__iter_就是一个可迭代类型. 实现__iter__
方法要求传入一个参数,为self(类自身的对象)返回一个迭代器 (iter( )函数,yield from iterable都可以返回一个迭代器)
__contains__(self,item) 使用判断语句 in 的时候调用的方法 如果使用 ” item in 对象 ” 就会调用这个方法
如果没有定义该方法依然可以使用,in 语句 自是他会自动调用 对象的 __iter__方法获取它的迭代器 相当于对对迭代器使用 in 语句. __contains__ 方法要求有返回值且为布尔型,若不为布尔型根据返回值是否为空类型返回True 或 False
索引访问 对象[ ] ,调用__getitem__方法 __getitem__(self,item) item为索引
形参只能为两个(如果不定义两个调用时将会出现无法处理的错误),item为传入中括号中的值,但系统对这个值要求非常松,可以为任意类型
使用索引赋值(赋值即定义) 对象[ ] =值 ,调用__setitem__方法 __setitem__(self,key,value) key为中括号中的值,value为等号右边的值
其他 __missing__, 当调用了__getitem__()方法,而key不存在就会调用这个方法(只能被动的调用)

总结:魔法方法,在使用中不像普通方法一样调用方法名就能够使用,他是系统中设置好的,我们在类中能够对它重写,对于运算符,重写的要求很简单,传入两个参数对于函数内部实现没有要求. 对于函数体实现没有要求.
对于容器类型的相关方法,它的参数可能要求很低,但使用中可能会出错,很多对于返回值也有要求,要求有且返回
指定类型. 实际在一个容器中,对于函数的实现它的要求其实会更高,例如它要实现索引设置和获取,要求把设置的内容保存,获取时从内部获取.基本数据类型中除了容器类型,还有其他类型实现了其中的部分方法

对象的打印,正常使用print函数打印一个对象会获得<__main__.A object at 0x00000272662DF6A0>这样的结果
__repr__ , __str__ 两个方法可以作为对象的显示方法
在print 和 format 函数中如果要打印对象会优先调用__str__方法, 如果打印一个包装了对象的基本数据类型的时候,会先执行打印基本数据类型的方法,其中的对象只会调用对象的__repr__方法

可调用对象__call__ 如果一个对象可以像函数一样的访问,因为实现了这个方法,对参数,返回值没有要求
__enter__,__exit__,使用条件苛刻,上下文管理(with语句)时才会执行,这两个方法都是被动调用的

@functools.total_ordering装饰器
类中实现包含等于,包含大于小于之一的两个方法就会实现六个方法

反射相关魔术方法:
首先看看反射相关的内建函数 getattr(对象,name[,default]) 通过name(字符串类型) 获取对象中叫作name的属性,没有就返回default,没设置会报错
setattr(对象,name,value) 设置对象的属性和值,有就覆盖,没有就新增
hasattr(对象,name) 判断对象是否有这个名字的属性
__getattr__(self,item) 外部对对象使用 对象.name 访问时,访问字典不能得到,最后执行的方法
__setattr__(self,key,value) 需要通过 对象.key = value 来为对象添加属性的时候自动调用,并拦截添加或覆盖操作,需要在其中重写这个方法,或用属性字典手动添加
__delattr__ 使用del语句删除对象时调用,并拦截删除
__getattribute__ 获取对象属性时会优先执行,如果要能正常执行获得真实结果返回
return object.__getattribute__(self.item)

总结:魔术方法,如果定义只要满足调用的条件就会自动的触发,暂时没有出现可以自行设置触发条件的魔术方法.
方法中,系统实现的部分直接或间接指示了参数含义,如果不顺着系统意思,在实际调用中可能会出现意想不到的错误. 类中的方法在实现时如果满足类中定义的魔术方法触发条件,将会触发. 魔术方法除了有方便应用和表达含义的符号,还有的实现特殊功能的,比如上下文管理 ,__call__外部访问,这些方法极大地扩展了类的功能.
显示和反射有关的魔术方法都属于工程,工具类型的魔术方法

描述器和它的三个魔术方法
:__get__ (self,instance,owner), __set__(self,instance,value) , __delete__(self, instance)
__get__ 外部的类的属性(类变量)访问就会调用,这个方法, 对象如果通过类变量访问,也会调用,它的返回值为访问到的值
__set__ 外部的类中设置对象属性值会调用,并拦截对象属性的设置

一个类中如果有这几个方法之一它就是一个描述器
如果一个类中的类属性(类变量)引入了一个描述器对象, 修饰器就能够作用于这个类. 满足条件的情况就会调用描述器中的方法. 分为很多情况
1,只有__get__, 描述器被类访问,会调用描述方法,且类变量的值为它的返回值,如果它对象通过类变量访问到修饰器,也会执行相同的操作
2,只有__set__, 在类的内部或外部,给类的对象添加或修改与描述器变量名相同的属性, 会触发描述器方法,它的返回值没有意义
3,有__del__, 在外部使用del 作用对象访问的,与描述器变量名想同的属性时,会调用 ,如果是用类访问到的不会调用

对于一个描述器有多个这样的方法,如果满足各自的条件就会触发访问,其中只有__get__为 非数据描述器
有__get__和__set__成为为数据描述器. 描述器的使用大概分为三块:1,定义描述器2,生成被描述的类并加载描述器3,外部调用被描述类的属性触发描述方法,后两种它可以起到对特定属性的监视作用.
数据描述器功能比非数据描述器强大

应用实例定义一个静态方法装饰器
class StaticMtd:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
print(‘get’)
return self.fn
def __set__(self, instance, value):
print(self,instance,value)
print(‘set’)
class A:
@StaticMtd # add = StaticMtd(add) 相当与引入了一个描述器
def add(x,y):
print(x,y)
A.add(4,5) #使用类访问触发描述器的方法
a =A()
a.add = 3 #使用对象添加与描述器变量名相同属性,触发set方法

]]>
/88806/feed 0
LVS-NAT+LVS-NAT基于NFS做wordpress负载均衡实验 /88805 /88805#respond Tue, 21 Nov 2017 12:32:17 +0000 /88805 Lvs-nat实验

实验设备:三台centos虚拟机

Director:DIP:10.0.0.254 VIP:192.168.208.129

RS1:RIP:10.0.0.1

RS2:RIP:10.0.0.2

 

首先都安装ipvsadm、telnet、httpd

 

  • 配置网卡:RS2:hostonly模式:10.0.0.2/24

aa

配置网卡:RS1:hostonly模式:10.0.0.1/24 方法同上nmtui 配置完使用ip add l查看

配置网卡:Director:ens33: VIP:192.168.208.129 DIP:10.0.0.254

bb

  • 在director上打开网卡间转发功能

vim /etc/sysctl.conf

添加net.ipv4.ip_forward=1

执行sysctl -p

 

  • 在RS1、RS2上分别编辑html文件

RS1:<h1>RS1</h1>

RS2:<h1>RS2</h1>

确保关闭防火墙,或者放行80端口

在Director上测试curl http://10.0.0.1 curl http://10.0.0.2

 

4、

[root@localhost ~]#ipvsadm -A -t 192.168.208.129:80 -s rr

[root@localhost ~]# ipvsadm -a -t 192.168.208.129:80 -r 10.0.0.1:80 -m -w 1

[root@localhost ~]# ipvsadm -a -t 192.168.208.129:80 -r 10.0.0.2:80 -m -w 2

轮询状态做负载均衡

cc

 

  • [root@localhost ~]# ipvsadm -E -t 192.168.208.129:80 -s wrr

以加权轮询做负载均衡

dd

ee

实验2:lvs-nat做WordPress的负载均衡

增加db服务器:RIP:10.0.0.3

Yum -y install mariadb-server nfs-utils

MariaDB [mysql]> CREATE DATDABASE wpdb;

MariaDB [mysql]> GRANT ALL PRIVILEGES ON wpdb.* TO ‘wpuser’@’%’ IDENTIFIED BY ‘wppass’;

MariaDB [mysql]> FLUSH PRIVILEGES;

 

[root@centos ~]# mkdir /nfs/app/ -pv

 

[root@centos ~]# cp wordpress-4.8.1-zh_CN.zip /nfs/app/

[root@centos ~]# cd /nfs/app

[root@centos app]# unzip wordpress-4.8.1-zh_CN.zip

[root@centos wordpress]# cp wp-config-sample.php wp-config.php

[root@centos wordpress]# vim wp-config.php

 

[root@centos wordpress]# id apache

uid=48(apache) gid=48(apache) groups=48(apache

看下是否存在Apache用户和Apache组,没有的话自己创建

[root@centos app]# chown -R apache:apache wordpress

 

vim /etc/exports

/nfs/app/wordpress 10.0.0.0/16(rw,async,anonuid=48,anongid=48)

 

[root@centos wordpress]# systemctl start nfs

[root@centos wordpress]# showmount -e 192.168.208.132

Export list for 192.168.208.132:

/nfs/app/wordpress 10.0.0.0/16

 

然后设置网卡

Ip改成10.0.0.3 gw10.0.0.254

 

 

在RS1和RS2上yum -y install nfs-utils

在director上做snat

[root@localhost ~]# iptablt nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT –to-source 192.168.208.129

还有给RS配DNS 要不然yum不了 – -ll

 

mount -t nfs 10.0.0.3:/nfs/app/wordpress /var/www/html/

 

 

 

 

 

 

 

]]>
/88805/feed 0
魔术方法 /88799 /88799#respond Tue, 21 Nov 2017 11:44:08 +0000 /88799
Edit

魔术方法

使用Python的魔术方法的最大优势在于他们提供了一种简单的方法来让对象可以表现的像内置类型一样。那意味着你可以避免丑陋的,违反直觉的,不标准的的操作方法。
特殊属性
属性
含义
__name__
类、函数、方法等名字
__module__
类定义所在的模块名?
__class__
对象或类所属的类
__bases__
类的基类的元组,顺序为它们在基类列表中出现的顺序
__doc__
类、函数的文档字符串,如果没有定义则为None
__mro__
类的mro,class.mro()返回的结果保存在__mro__中
__dict__
类或实例的属性,可写的字典
查看属性
方法
意义
__dir__
返回类或者对象的所有成员名称列表.dir()函数就是调用__dir__().如果提供了__dir__(),则返回属性的列表,否则就会尽量从__dict__属性中收集信息
  • 如果dir([obj])参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。
  • dir()对于不同类型的对象具有不同的行为
  • 如果对象是模块对象,列表包含模块的属性名
  • 如果对象是类型或者类对象,列表包含类的属性名,及它的积累的属性名
  • 否则,列表包含对象的属性名,它的类的属性名和类的基类的属性名
import animal
from animal import Animal
class Cat(Animal):
y = ‘cat’
x = ‘abcd’
class Dog(Animal):
def __dir__(self):
return [‘dog’]
print(‘————————‘)
print(‘Current Module\’s name = {}’.format(dir()))#模块名词空间内的属性
print(‘Animal Module\’s name = {}’.format(dir(animal)))#animal模块名词空间的属性
print(“object’s dict={}”.format(sorted(object.__dict__.keys())))#object字典内容
print(“Animal’s dir()={}”.format(dir(Animal)))#类名词空间下的属性方法
print(‘Cat dirr()={}’.format(dir(Cat)))#类Cat的dir()
print(‘————————‘)
tom = Cat(‘tome’)
print(sorted(dir(tom)))#实例tom的属性,Cat类及所有祖先的类属性
print(sorted(tom.__dir__()))#同上
#dir()的等价,近似如下,__dict__字典中几乎包括了所有属性
print(sorted(set(tom.__dict__.keys())|set(Cat.__dict__.keys())|set(object.__dict__.keys())))
print(‘Dog dir = {}’.format(dir(Dog)))
dog = Dog(‘snoppy’)
print(dir(dog))
print(dog.__dict__)
———————————–
{‘_name’: ‘Thunk’, ‘weight’: 10, ‘_Animal__age’: 20}
[‘_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_name’, ‘weight’, ‘x’]
————————
Current Module’s name = [‘Animal’, ‘Cat’, ‘Dog’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘animal’]
Animal Module’s name = [‘Animal’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘c’]
object’s dict=[‘__class__’, ‘__delattr__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’]
Animal’s dir()=[‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’]
Cat dirr()=[‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’, ‘y’]
————————
[‘_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_name’, ‘weight’, ‘x’, ‘y’]
[‘_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_name’, ‘weight’, ‘x’, ‘y’]
[‘_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘_name’, ‘weight’, ‘x’, ‘y’]
Dog dir = [‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’]
[‘dog’]
{‘_name’: ‘snoppy’, ‘weight’: 10, ‘_Animal__age’: 20}
魔术方法
  • 分类:
    • 创建与销毁
      • __init__与__del__
    • hash
    • bool
    • 可视化
    • 运算符重载
    • 容器和大小
    • 可调用对象
    • 上下文管理
    • 反射
    • 描述器
    • 其他杂项
Hash
方法
意义
__hash__
内建函数hash()调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash
class A:
def __init__(self):
self.a = ‘a’
self.b = ‘b’
def __hash__(self):
return 1
def __eq__(self, other):
return self.a == other.a
print(hash(A()))
print((A(),A()))
print({A(),A()})
s = {A(),A()}
print(s)
——————————-
1
(<__main__.A object at 0x000000872C048278>, <__main__.A object at 0x000000872C048390>)
{<__main__.A object at 0x000000872C048278>}
{<__main__.A object at 0x000000872C048278>}
other的解释:
class A:
def __init__(self):
self.a = ‘a’
self.b = ‘c’
def __hash__(self):
return 1
def __eq__(self, other):
# if not isinstance(other,A):
# return False
return self.a == other.a
class B:
def __init__(self):
self.a = ‘a’
self.b = ‘b’
def __eq__(self, other):
return self.b == other.b
class C:
c = ‘c’
a = A()
c = a
b = B()
print(a == b)#用a的eq方法与b的other.a比较由于都是“a”所以为ture
print(a is c)#
print(id(a), id(c))#id相同因为c对象为a的引用
print(b == C)#如果b在前则使用b的eq方法,由于C类没有定义b属性所以报错
———————-
Traceback (most recent call last):
True
File “F:/pycharm_product/python/1113/1.py”, line 28, in <module>
157269657528 157269657528
print(b == C)#如果b在前则使用b的eq方法,由于C类没有定义b属性所以报错
File “F:/pycharm_product/python/1113/1.py”, line 17, in __eq__
return self.b == other.b
AttributeError: type object ‘C’ has no attribute ‘b’
  • hash值相同不代表对象相同,比如hash算法为%3取模,此时3,6,9的hash值相同但是对象并不相同。
set去重会先判断is是否相同,如果不同再判断==是否相同,如都不同则会放到集合中
In [52]: b = (1,2,3)
In [53]: a = (1,2,3)
In [54]: id(b)
Out[54]: 917501314464
In [55]: id(a)
Out[55]: 917522737264
In [56]: c = {a,b}
In [57]: c
Out[57]: {(1, 2, 3)}#虽然内存地址不同但是内容相同还是做了去重处理
方法
意义
__eq__
对应==操作符,判断2个对象是否相等返回bool值
  • __hash__方法只是返回一个hash值作为set的key,但是去重,还需要__eq__来判断对象是否相等。
  • hash值相等,只是hash冲突,不能说明两个对象是相等的
  • 因此,一般来说hash方法是为了作为set或者dict的key,所以去重同时需要eq方法
  • 可hash对象昂必须提供__hash__方法,没有提供的话,instance(p1,collections.Hashable)一定为False。去重要提供__eq__方法。
  • 练习:
  • 设计二维坐标Point,比较2个坐标是否相等?
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
a = Point(3,4)
c = Point(3,4)
d = Point(4,5)
print(a == c)
print(a == d)
print(a is c)
print(a is d)
———————-
True
False
False
False
  • 思考:为什么list不可以hash?
Alt text
* 通过查看原码发现__hash__ = None,也就是说如果调用__hash__()相当于调用None(),一定报错
* 所有的类都继承了object,而这个类是具有__hash__()方法的,如果一个类不能被hash,就把hash设置为None
bool
  • 四大皆空<list,tuple,set,dict>,__len__()为0所以必定为False
方法
意义
__bool__
内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。没有定义__bool__(),就找__len__()返回长度,非0为真。如果__len__()也没有定义,那么所有实例都返回真
class A:
pass
print(bool(A()))
class B:
def __bool__(self):
return False
print(bool(B))
print(bool(B()))
class C:
def __len__(self):
return 0
print(bool(C()))
——————–
True
True
False
False
可视化
方法
意义
__repr__
内建函数repr()对一个对象获取字符串表达。如果一个类定义了__repr__()但没有定义__str__,那么在请求该类的‘非正式’的字符串表示时也将调用__repr__()
__str__
str()函数,内建函数format、print()函数调用,需要返回对象的字符串表达
__bytes__
bytes的时候,返回一个对象的bytes表达,即返回bytes对象
class A:
def __init__(self):
self.a = ‘a’
self.b = ‘b’
def __repr__(self):
return ‘repr:{},{}’.format(self.a,self.b)
def __str__(self):
return ‘str:{},{}’.format(self.a,self.b)
print(A())#print函数使用__str__
print([A()])#[]使用__str__,但其内部使用__repr__
print(([str(A())]))#[]使用__str__,str()函数也使用__str__
print(‘str:a,b’)
s = ‘b’
print([‘a’],(s,))
——————–
str:a,b
[repr:a,b]
[‘str:a,b’]
str:a,b
[‘a’] (‘b’,)
运算符重载
  • operator模块提供一下的特殊方法,可以将类的实例使用下面的操作符来操作
运算符
特殊方法
含义
<,<=,==,>,>=,!=
__lt__,__le__,__eq__,__gt__,__ge__,__ne__
比较运算符
+,-,*, /,%,//,**,divmod
__add__,__sub__,__mul__,__truediv__,__mod__,__floordiv__,__pow__,__divmod__
算数运算符,位运算符也有对应的方法
+=,-=,*=,/=,%=,//=,**=
__iadd__,__isub__,__imul__,__itruediv__,__imod__,__floordiv__,__ipow__
class A:
def __init__(self,x):
self.x = x
def __sub__(self, other):
return self.x – other.x
def __isub__(self, other):
tmp = self.x – other.x
return A(tmp)
def __str__(self):
return str(self.x)
x = A(5)
y = A(4)
print(x – y,x.__sub__(y))#直接使用减法跟调用sub方法效果一样,运算符重载
x -= y#实例化对象调用运算符
print(x)
—————————————–
1 1
1
  • 练习:完成Point类设计,实现判断点相等的方法,并完成向量的加法
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __repr__(self):
return ‘self.x={},self.y={}’.format(self.x,self.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __add__(self, other):
return self.x+other.x,self.y+other.y
def add(self,other):
return Point(self.x + other.x,other.y + self.y)
p1 = Point(1,1)
p2 = Point(1,1)
points = (p1,p2)
print(points[0].add(points[1]))
#运算符重载
print(points[0] + points[1])
#print(Point(*(points[0] + points[1])))提示*的选项不可迭代,原因是上面的__add__魔术方法中的return为Point(self.x+other.x,self.y+other.y)对象
print(p1 == p2)
运算符重载应用场景
  • 往往是用面向对象实现的类,需要做大量的运算,而运算符是这种在数学上最常见的表达方式。例如,上例中的对+进行了运算符重载,实现了Point类的二元操作,重新定义为Point+Point
  • 提供运算符重载,比直接提供加法方法要更加适合该领域内使用者的习惯
  • int类,几乎实现了所有操作符
容器的相关方法
方法
意义
__len__
内建函数len(),返回对象的长度(>0的整数),其实即使把对象当做容器类型看,就如同list或者dict。bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回非0为真
__iter__
迭代容器时,调用,返回一个新的迭代器对象
__contains__
in成员运算符,没有实现,就调用__iter__方法遍历
__getitem__
实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于set和dict,key为hashable。key不存在引发keyError异常
__setitem__
和__getitem__的访问类似,是设置值得方法
__missing__
‘字典使用’__getitem__()调用时,key不存在执行该方法
*练习:将购物车改造成方便操作的容器类
class Cart:
def __init__(self):
self.items = []#定义购物车容器
def __len__(self):
return len(self.items)#返回对象长度
def additem(self,item):
self.items.append(item)#向购物车内添加商品
def __add__(self, other):#运算符重载,实例化后使用+即代表add
self.items.append(other)
return self
def __getitem__(self, index):#实例化对象通过索引获取value
return self.items[index]
def __setitem__(self,key,value):#实例化对象通过索引方式设置value
print(key,value)
self.items[key] = value
#self.[key] = value#不可以
def __iter__(self):#迭代和in注意要求返回必须是一个迭代器
return iter(self.items)#将列表容器转为装饰器对象,需要for或next获取内容
def __repr__(self):
return str(self.items)
cart = Cart()
cart.additem(1)
cart.additem(‘a’)
cart.additem(2)
print(len(cart))
print(‘~’*40)
for x in cart:
print(x)
print(‘~’*40)
print(2 in cart)#in操作,这个例子没有实现contains方法,就调用iter方法遍历
print(cart[1])#索引操作即调用getitem方法
cart[2] = ‘b’#调用setitem方法
print(cart[2])
print(cart + 2 + 3 + 4 + 5)#链式变成实现加法
cart.__add__(2).__add__(3)
print(‘~’*40)
for i in cart:
print(i)
print(cart.items)
———————–
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1
a
2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
True
a
2 b
b
[1, ‘a’, ‘b’, 2, 3, 4, 5]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1
a
b
2
3
4
5
2
3
[1, ‘a’, ‘b’, 2, 3, 4, 5, 2, 3]
可调用对象
  • python中一切皆对象,函数也不例外
def foo():
print(foo.__module__,foo.__name__)
foo()#跟下面等价
foo.__call__()
———————-
__main__ foo
__main__ foo
  • 函数即对象,对象foo加上(),就是调用对象的__call__()方法
  • 可调用对象
方法
意义
__call__
类中的第一个该方法,实例就可以像函数一样调用
  • 可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用。
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self, *args, **kwargs):
return “Point({},{})”.format(self.x,self.y)
p = Point(4,5)
print(p)
print(p())
class Adder:
def __call__(self, *args):
ret = 0
for x in args:
ret += x
self.ret = ret
return ret
adder = Adder()
print(adder(4,5,6))
print(adder.ret)
————————
<__main__.Point object at 0x0000004F80B98780>
Point(4,5)
15
15
  • 练习:定义一个斐波那契数列的类,方便调用,计算第n项
#想法一,交换值
class Fib():
def __init__(self):
self.x = 0
self.y = 1
self.z = 0
self.fib = [0,1]
def __call__(self, *args, **kwargs):#由于args返回为一个tuple所以需要解构或者取第一个值
self.f = args[0]
for _ in range(2,self.f+1):
self.z = self.x + self.y
self.x = self.y
self.y = self.z
return self.z
fib = Fib()
print(fib(5))
—————-
5
#方法二,优势当传入60,再传入40时返回速度很快,因为第二个if将已存在的index直接取出
class Fib:
def __init__(self):
self.items = [0,1,1]
def __call__(self, index):
if index < 0:
raise IndexError(‘Wrong Index’)
if index < len(self.items):
return self.items[index]
for i in range(3,index+1):
self.items.append(self.items[i-1] + self.items[i-2])
return self.items[index]
print(Fib()(4))
#方法三:使用容器方法来实现,使用类实现斐波那契很好实现,还可以缓存数据,便于检索
class Fib:
def __init__(self):
self.items = [0,1,1]
def __call__(self, index):
return self[index]
def __iter__(self):
return iter(self.items)
def __len__(self):
return len(self.items)
def __getitem__(self, index):
if index < 0:
raise IndexError(‘Wrong Index’)
if index < len(self.items):
return self.items[index]
for i in range(len(self),index+1):
self.items.append(self.items[i-1] + self.items[i-2])
return self.items[index]
def __str__(self):
return str(self.items)
__repr__ = __str__
fib = Fib()
print(fib(5),len(fib))
print(fib(10),len(fib))
for x in fib:
print(x)
print(fib[5],fib[6])
上下文管理
  • 文件IO操作可以对文件对象使用上下文管理,使用with…as语法
with open(‘test’) as f:
pass
#仿照文件操作写一个类,实现上下文管理
class Point:
pass
with Point() as p:#AttributerError:__exit__,添加完exit后又报enter继续添加
pass
  • 上下文管理对象
  • 当一个对象同时实现了__enter__和__exit__()方法,它就属于上下文管理的对象
方法
意义
__enter__
进入与此对象相关的上下文,如果存在该方法,with语法会把该方法的返回值作为绑定到as子句中指定的变量上
__exit__
退出与此对象相关的上下文
#实例化对象上下文管理
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self, exc_type, exc_val, exc_tb):
print(‘exit’)
with Point() as f:
print(‘do sth.’)
  • 实例化对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法
  • with可以开启一个上下文运行环境,在执行前做一些准备,执行后做一些收尾工作
上下文管理的安全性
  • 看看异常对上下文的影响,通过下例可以看出在enter和exit照样执行,上下文管理是安全的
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self, exc_type, exc_val, exc_tb):
print(‘exit’)
with Point() as f:
raise Exception(‘error’)
print(‘do sth.’)
—————————–
Traceback (most recent call last):
init
File “F:/pycharm_product/python/1115/8.py”, line 12, in <module>
enter
raise Exception(‘error’)
exit
Exception: error
  • 极端例子:调用sys.exit(),它会退出当前解释器
  • 打开Python解释器,在里面敲sys.exit(),窗口直接关闭了,也就是说碰到这一句,Python运行环境直接退出了
import sys
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self, exc_type, exc_val, exc_tb):
print(‘exit’)
with Point() as f:
sys.exit()
print(‘do sth.’)
print(‘outer’)
———————–
init
enter
exit
  • 从执行结果来看,依然执行了__exit__函数,哪怕是退出Python运行环境
  • 由此说明上下文管理很安全
with语句
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self, exc_type, exc_val, exc_tb):
print(‘exit’)
p = Point()
with p as f:
print(p == f)#不相等
print(‘do sth.’)
———————————
init
enter
False
do sth.
exit
  • 不相等的原因在于__enter__方法上,它将自己的返回值赋给了f,继续修改测试看下例
import sys
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
return self#加上此句则p与f相等
def __exit__(self, exc_type, exc_val, exc_tb):
print(‘exit’)
p = Point()
with p as f:
print(p == f)
print(p is f)
print(‘do sth.’)
——————
init
enter
True
True
do sth.
exit
  • __enter__方法返回值就是上下文使用的对象,with语法会把它的返回值赋给as子句的变量
  • __enter__方法和__exit__方法的参数
  • __enter__方法没有其他参数
  • __exit__方法有三个参数(self.exctype,excvalue,traceback)
  • 这三个参数都与异常有关
  • 如果该上下文退出时没有异常,这三个参数都是None
  • 如果有异常,参数意义如下:
    • exc_type:异常类型
    • exc_value:异常的值
    • traceback,异常的追踪信息
    • __exit方法返回一个等效True的值,则压制异常;否则继续抛出异常
import sys
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(exc_type)
print(exc_val)
print(exc_tb)
print(‘exit’)
return ‘abc’
p = Point()
with p as f:
raise Exception(‘New Error’)
print(‘do sth.’)
print(‘outer’)
——————————-
init
enter
<class ‘Exception’>
New Error#获取到的错误值
<traceback object at 0x000000517DA3BE88>
exit
outer
  • 练习:为加法函数计时
  • 1.使用装饰器显示该函数的执行时长
  • 2.使用上下文管理显示该函数的执行时长
#装饰器实现
import datetime
from functools import wraps
import time
def timeit(fn):
@wraps(fn)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
ret = fn(*args,**kwargs)
delta = (datetime.datetime.now() – start).total_seconds()
print(‘{} took {}s’.format(fn.__name__,delta))
return ret
return wrapper
@timeit
def add(x,y):
time.sleep(2)
return x+y
print(add(4,5))
#安全上下文实现:
import datetime
from functools import wraps
import time
def timeit(fn):
@wraps(fn)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
ret = fn(*args,**kwargs)
delta = (datetime.datetime.now() – start).total_seconds()
print(‘{} took {}s deco ‘.format(fn.__name__,delta))
return ret
return wrapper
@timeit
def add(x,y):
time.sleep(2)
return x+y
class TimeIt:
def __init__(self,fn):
self.fn = fn
def __enter__(self):
self.start = datetime.datetime.now()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(‘{} took {}s context’.format(self.fn.__name__,self.delta))
pass
def __call__(self, x,y):
print(x,y)
return self.fn(x,y)
# with TimeIt(add):
# add(4,5)
with TimeIt(add) as foo:
foo(4,5)
——————————————————————-
#把类当做装饰器用
import datetime
from functools import wraps
import time
class TimeIt:
def __init__(self,fn):
self.fn = fn
def __call__(self, *args,**kwargs):
self.start = datetime.datetime.now()
ret = self.fn(*args,**kwargs)
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(‘{} took {}s. call’.format(self.fn.__name__,self.delta))
return ret
@TimeIt
def add(x,y):
time.sleep(2)
return x+y
add(4,5)
print(add.__doc__)
——————————-
add took 2.000316s. call
None#无法获取被装饰函数的原属性,如文档字符串
———————————————————————-
##解决无法显示被装饰函数的字符串文档问题,原始方法可以将init中加入self.__doc__=fn.__doc__,不过这样繁琐且不全面
import datetime
from functools import wraps
import time
class TimeIt:
def __init__(self,fn):
self.fn = fn
wraps(fn)(self)#
def __call__(self, *args,**kwargs):
self.start = datetime.datetime.now()
ret = self.fn(*args,**kwargs)
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(‘{} took {}s. call’.format(self.fn.__name__,self.delta))
return ret
@TimeIt
def add(x,y):
“””This is add func”””
time.sleep(2)
return x+y
add(4,5)
print(add.__doc__)
上下文应用场景
1.增强功能:在代码执行的前后增加代码,以增强其功能,类似装饰器的功能
2.资源管理:打开了资源需要关闭,例如文件对象,网络连接,数据库连接等
3.权限验证:在执行代码前,做权限的验证,在__enter__中处理
contextlib.contextmanager
  • 它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现__enter__和__exit__方法
  • 对下面的函数有要求,必须有yield,也就是说这个函数必须返回一个生成器,且只有yield一个值
import contextlib
@contextlib.contextmanager
def foo():
print(‘enter’)
yield
print(‘exit’)
with foo() as f:
#raise Exception()只能打印enter无法执行yield和exit
print(f)
—————————-
enter
None
exit
  • f接收yield语句的返回值
  • 下面增加一个异常,发现不能保证exit执行,解决办法:增加try finally。
import contextlib
@contextlib.contextmanager
def foo():
print(‘enter’)
try:
yield#yield 5,yield的值只能有一个,作为__enter__方法的返回值
finally:
print(‘exit’)
with foo() as f:
raise Exception()
print(f)
————————-
Traceback (most recent call last):
enter
exit
File “F:/pycharm_product/python/1117/1.py”, line 12, in <module>
raise Exception()
Exception
  • 这样做得意义是,当yield发生处为生成器函数增加了上下文管理
import contextlib
import datetime
import time
@contextlib.contextmanager
def add(x,y):
start = datetime.datetime.now()
try:
yield x + y#yield 5,yield的值只能有一个,作为__enter__方法的返回值
finally:
delta = (datetime.datetime.now() – start).total_seconds()
print(delta)
with add(4,5) as f:
#raise Exception()
time.sleep(2)
print(f)
———————————–
9
2.000035
总结:如果业务逻辑简单可以使用函数加装饰器方式,如果业务复杂,用类的方式加__enter__和__exit__
反射
  • 概述:
    • 运行时,区别于编译时,指的是程序被加载到内容中执行的时候
    • 反射,reflection,指的是运行时获取类型定义信息
    • 一个对象能够在运行时,像照镜子一样,反射出其类型信息
    • 简单说,在python中,能够通过一个对象,找出其type、class、attribute或method的能力,成为反射或者自省
  • 反射相关函数和方法
  • 需求:有一个Point类,查看它实例的属性,并修改它,动态为实例加属性
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __str__(self):
return “Point({},{})”.format(self.x,self.y)
def show(self):
print(self.x,self.y)
p = Point(4,5)
print(p)
print(p.__dict__)
p.__dict__[‘y’] = 6
print(p.__dict__)
p.z = 10
print(p.__dict__)
print(‘~’*40)
print(dir(p))
print(‘~’*40)
print(p.__dir__())
—————————————–
Point(4,5)
{‘x’: 4, ‘y’: 5}
{‘x’: 4, ‘y’: 6}
{‘z’: 10, ‘x’: 4, ‘y’: 6}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘show’, ‘x’, ‘y’, ‘z’]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[‘z’, ‘__ge__’, ‘__ne__’, ‘__delattr__’, ‘__le__’, ‘x’, ‘__str__’, ‘__format__’, ‘__eq__’, ‘__init__’, ‘__weakref__’, ‘__class__’, ‘__dir__’, ‘__getattribute__’, ‘__reduce__’, ‘__new__’, ‘__dict__’, ‘__hash__’, ‘__subclasshook__’, ‘__reduce_ex__’, ‘__sizeof__’, ‘__setattr__’, ‘show’, ‘__repr__’, ‘y’, ‘__gt__’, ‘__doc__’, ‘__module__’, ‘__lt__’]
  • 上例通过属性字典__dict__来访问对象的属性,本质上也是利用的反射能力
  • python提供了内置的函数
内置函数
意义
getattr(object,name[,default])
通过name返回object的属性值,当属性不存在,将使用defalut返回,如果没有default,则抛出AttributeError。name必须为字符串
setattr(object,name,value)
object的属性存在,则覆盖,不存在,新增
hasattr(object,name)
判断对象是否有这个名字的属性,name必须为字符串
#测试getattr,setattr,hasattr
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __str__(self):
return “Point({},{})”.format(self.x,self.y)
def show(self):
print(‘3’)
p1 = Point(4,5)
p2 = Point(10,10)
#getattr(Point,’show’)()#类无法调用自己的方法,可以使用类方法来增加类调用功能
print(repr(p1),repr(p2),sep=’\n’)
print(p1.__dict__)
setattr(p1,’y’,16)
setattr(p1,’z’,10)
print(getattr(p1,’__dict__’))
#动态调用方法如果show方法存在则调用
if hasattr(Point,’show’):
getattr(p1,’show’)()#getattr可以处理类或者实例化的对象
#动态增加方法
#为类增加方法
if not hasattr(Point,’add’):
setattr(Point,’add’,lambda self,other:Point(self.x+other.x,self.y+other.y))
print(Point.__dict__)
print(‘~’*40)
print(Point.add)
print(p1.add)
print(p1.add(p2))#绑定
print(‘~’*40)
#为实例增加方法,未绑定
if not hasattr(p1,’sub’):
setattr(p1,’sub’,lambda self,other:Point(self.x-other.x,self.y-other.y))
print(p1.sub(p1,p1))
print(p1.sub)
#add在谁里面,sub在谁里面
print(p1.__dict__)
print(Point.__dict__)
————————————–
<__main__.Point object at 0x000000B0E7EA89B0>
<__main__.Point object at 0x000000B0E7EA89E8>
{‘x’: 4, ‘y’: 5}
{‘x’: 4, ‘y’: 16, ‘z’: 10}
3
{‘__init__’: <function Point.__init__ at 0x000000B0E7E9B7B8>, ‘show’: <function Point.show at 0x000000B0E7E9B8C8>, ‘__dict__’: <attribute ‘__dict__’ of ‘Point’ objects>, ‘__weakref__’: <attribute ‘__weakref__’ of ‘Point’ objects>, ‘__module__’: ‘__main__’, ‘__str__’: <function Point.__str__ at 0x000000B0E7E9B840>, ‘__doc__’: None, ‘add’: <function <lambda> at 0x000000B0E7E9B730>}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<function <lambda> at 0x000000B0E7E9B730>
<bound method <lambda> of <__main__.Point object at 0x000000B0E7EA89B0>>
Point(14,26)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Point(0,0)
<function <lambda> at 0x000000B0E7E9B950>
{‘sub’: <function <lambda> at 0x000000B0E7E9B950>, ‘y’: 16, ‘z’: 10, ‘x’: 4}
{‘__init__’: <function Point.__init__ at 0x000000B0E7E9B7B8>, ‘show’: <function Point.show at 0x000000B0E7E9B8C8>, ‘__dict__’: <attribute ‘__dict__’ of ‘Point’ objects>, ‘__weakref__’: <attribute ‘__weakref__’ of ‘Point’ objects>, ‘__module__’: ‘__main__’, ‘__str__’: <function Point.__str__ at 0x000000B0E7E9B840>, ‘__doc__’: None, ‘add’: <function <lambda> at 0x000000B0E7E9B730>}
上例中的绑定和未绑定?
  • 思考:这种动态增加属性的方式和装饰器修饰一个类、Mixin方式的差异?
  • 这种动态增删属性的方式是运行时改变类或者实例的方式,但是装饰器或者Mixin都是定义时就决定了,因此反射能力具有更大的灵活性
  • 练习
  • 1.命令分发器,通过名称找对应的函数执行。思路:名称找对象的方法
#方法一:函数实现分发器
def dispatcher():
cmds = {}
def reg(cmd,fn):
if isinstance(cmd,str):
cmds[cmd] = fn
else:
print(‘error’)
#print(cmds)#查看字典中的内容,cmd:lambda内存地址
def run():
while True:
cmd = input(“plz input command:”)
if cmd.strip() == ‘quit’:
return
cmds.get(cmd.strip(),defaultfn)()#get得到一个函数方法所以后面需要加()来调用,如果get不存在的key则返回默认的defaultfn函数。
def defaultfn():
pass
return reg,run
reg,run = dispatcher()
reg(‘cmd1’,lambda :1)
reg(‘cmd2’,lambda :2)
run()
#方法二:用类方法实现分发器
#类实现分发器:
#1.注册方法
#2.执行方法
class Dispatcher():
def __init__(self):
self._run()#不用实例化也能用?,其实在类的调用中已经实例化,只不过没将实例化的对象赋给一个名字
def cmd1(self):
print(“I’m cmd1”)
def cmd2(self):
print(“I’m cmd2”)
def _run(self):
while True:
cmd = input(“please input key”)
if cmd.strip() == “quit”:
break
getattr(self,cmd,lambda : print(‘Unknown Command {}’.format(cmd)))()
Dispatcher()
#print(Dispatcher.__dict__)
  • 方法二中,使用getattr方法找到对象的属性的方式,比自己维护一个字典来建立名称和函数之间的关系好得多
反射相关的魔术方法
  • __getattr__()、__setattr__()、__delattr__(),三个魔术方法
  • __getattr__()测试:
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print(self.x,self.y)
def __getattr__(self, item):
return “missing {}”.format(item)
p1 = Point(4,5)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
————————-
4
6
0
missing t
一个类的属性会按照继承关系找,如果找不到,就会执行getattr方法,如果没有这个方法,就会抛出AttributeError异常表示找不到属性
查找属性顺序为:
instance.dict—>instance.class.dict—>继承的祖先类(直到object)的dict—>调用getattr()
  • __setattr__()举例:
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print(self.x,self.y)
def __getattr__(self, item):
return “missing {}”.format(item)
def __setattr__(self, key, value):
print(“setattr {} ={}”.format(key,value))
p1 = Point(4,5)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
p1.x = 50
print(p1.__dict__)
p1.__dict__[‘x’] = 60
print(p1.__dict__)
print(p1.x)
—————————
setattr x =4
setattr y =5
missing x
6
0
missing t
setattr x =50
{}#因为setattr魔术方法对拦截属性的添加,修改操作所以x,y都没在字典中
{‘x’: 60}
60
实例通过点设置属性,如同self.x = x,就会调用__setattr__(),属性要加到实例的dict中,就需要自己完成
setattr方法,可以拦截实例属性的添加、修改操作,如果要设置生效,需要自己操作实例的dict,此例子中需要再setattr函数中加入self.__dict__[key] = value
  • __delattr__()举例:
class Base:
n = 0
class Point(Base):
Z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def __delattr__(self, item):
print(‘Can not del {}’.format(item))
p = Point(14,5)
del p.x
p.z = 15
del p.z
del p.Z
print(Point.__dict__)
print(p.__dict__)
del Point.Z
print(Point.__dict__)
——————————
Can not del x
Can not del z
Can not del Z
{‘__doc__’: None, ‘__delattr__’: <function Point.__delattr__ at 0x0000002959D3B7B8>, ‘Z’: 6, ‘__module__’: ‘__main__’, ‘__init__’: <function Point.__init__ at 0x0000002959D3B730>}
{‘x’: 14, ‘y’: 5, ‘z’: 15}
{‘__doc__’: None, ‘__delattr__’: <function Point.__delattr__ at 0x0000002959D3B7B8>, ‘__module__’: ‘__main__’, ‘__init__’: <function Point.__init__ at 0x0000002959D3B730>}
可以阻止通过实例删除属性的操作。但是通过类依然可以删除属性。如同Z
  • __getattribute__举例:
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def __getattr__(self, item):
return “missing {}”.format(item)
def __getattribute__(self, item):
return item
p1 = Point(4,5)
print(p1.__dict__)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
print(Point.__dict__)
print(Point.z)
————————————
__dict__
x
z
n
t
{‘__init__’: <function Point.__init__ at 0x0000000100FCB730>, ‘__doc__’: None, ‘z’: 6, ‘__module__’: ‘__main__’, ‘__getattribute__’: <function Point.__getattribute__ at 0x0000000100FCB840>, ‘__getattr__’: <function Point.__getattr__ at 0x0000000100FCB7B8>}
6
  • 实例的所有的属性访问,第一个都会调用getattribute方法,它阻止了属性的查找,该方法应该返回(计算后的)值或者抛出一个AttributeError异常
  • 他的return值将作为属性查找的结果,如果抛出AttributError异常,则会直接调用getattr方法,因为表示属性没有找到
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def __getattr__(self, item):
return “missing {}”.format(item)
def __getattribute__(self, item):
# raise AttributeError(‘Not Found’)
# pass
# return self.__dict__[item]
return object.__getattribute__(self,item)
p1 = Point(4,5)
print(p1.__dict__)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
print(Point.__dict__)
print(Point.z)
————————————-
{‘y’: 5, ‘x’: 4}
4
6
0
missing t
{‘__getattribute__’: <function Point.__getattribute__ at 0x00000068B1D3B840>, ‘__doc__’: None, ‘__init__’: <function Point.__init__ at 0x00000068B1D3B730>, ‘z’: 6, ‘__getattr__’: <function Point.__getattr__ at 0x00000068B1D3B7B8>, ‘__module__’: ‘__main__’}
6
  • getattribute方法中为了避免在该方法中无限递归,他的实现应该永远调用基类的同名方法以访问需要的任何属性,例如object.getattribute(self,name).
  • 注意:除非你明确的知道getattribute方法用来做什么,否则不要使用它
总结:
魔术方法
意义
__getattr__()
通过搜索实例、实例的类及祖先类查不到属性,就会调用此方法
__setattr__()
通过.访问实例属性,进行增加、修改都要调用它
__delattr__()
当通过实例来删除属性时调用此方法
__getattribute__()
实例所有的属性调用都从这个方法开始
  • 属性查找顺序
  • 实例调用__getattribute__()–>instance.__dict__–>instance.__class__.__dict__–>继承祖先类(直到object)的__dict__–>调用__getattr__()
]]>
/88799/feed 0
20171121 grep 正则表达式 /88798 /88798#respond Tue, 21 Nov 2017 08:35:30 +0000 /88798 一、diff 与 patch

1. diff 用来对比两个文件的差异,并输出出来保存在一种“补丁文件”中:

diff

2.diff -u 通过-u选项来输出统一的“unfied 模式”

diff2

3.patch -b自动备份改变了的文件

4.利用diff -u和patch -b来复制文件

diff1

二、作业:

1.找出ifconfig “网卡名”命令结果中本机的 IPv4 的地址

ifconfig ens33|grep netmask|tr -s ” “|cut -d ” ” -f3

2.查出分区空间使用率的最大百分比值

df|grep / |tr -s ” “|cut -d ” ” -f5|sort -n|tail -n1

df

3.查出用户UID最大值的用户名、UID及shell类型

getent passwd|cut -d: -f1,3,7|sort -n -t: -k2|tail -1

df1

三、grep命令

1. grep、sed、awk号称文件编辑的三剑客

2. grep在CentOS 6和CentOS 7中是不一样的,在CentOS 6上面grep是一个内部命令:

g1

在CentOS 7上面是一个别名 :

g2

3.

基本用法:grep 可以使用以行为单位,键盘输入,然后过滤,再显示出匹配结果

g3

grep +文件 可以用来匹配文件内的内容

g4

同样grep支持键盘输入,也就支持管道技术

g5

grep 可以后接命令,grep + ` `

g6

4. 选项

-v 与匹配的内容,恰恰相反

g7

-i 不检查大小写

g8

-n 显示出包含字符串的行号

g9

-c 统计匹配到的次数

g10

-q 静默模式,就是匹配出来,但是什么都不显示

g11

-o 仅显示你搜索到的字符串

g12

-e 或的关系 类如-e djj -e

-w 匹配整个单词

四、正则表达式:

1. 相对于文件的通配符而言,正则表达式是用来匹配字符串的,而通配符是用来匹配文件名称。 它是有一类的特殊字符编写的,其中的字符不一定表示字面意思,而是表示控制或通配的作用。

2. 正则表达式分两类:基本正则表达式和扩展正则表达式

3. 元字符的分类:字符匹配,匹配次数,匹配位置,分组

 

字符匹配: . 表示任意字符

z

[ abc ] 表示abc中的任何其中一个字符

z1

[^] 匹配除了符合条件的任意一个字符

z3

[:alnum:]代表字母和数字 [:alpha:]代表任何英文大小写字符

[:lower:]小写字母 [:upper:]大写字母

[:blank:]空白字符(空格和制表符)[:space:]水平和垂直的制表符(比[:blank:] 范围更大)

匹配次数:用在指定次数的字符后面,用于指定前面字符要出现的次数

*任意次数,.*就表示任意字符的任意的次数

z4

\?匹配其前面的字符0或1次

z5

z6

\+匹配其前面的字符至少一次

z7

z8

\{n\}匹配前面的字符n次

z9

\{,n\}匹配前面的字符至多n次

zi

\{n,\}匹配前面的字符至少n次

zi1

匹配位置:

一行中: ^ 行首锁定 $行尾锁定

单词行: \<或\b锁定词首 \> 或 \b词尾锁

 

 

 

 

 

]]>
/88798/feed 0
友情链接:万达娱乐注册  万达招商  万达娱乐招商  万达主管  万达娱乐招商QQ  万达娱乐开户  万达直属  万达开户  guoqibee.com  万达娱乐直属QQ