有关于Python基础(一) 见:https://blog.csdn.net/Tester_xjp/article/details/78971608
其中包含了,基础语法,基本类型的一些操作和方法,以及类和类型,继承,函数,与异常等基础知识
本篇小编就从魔法方法,开始介绍python基础
一、魔法(特殊)方法
a.__init__构造方法(魔法方法的一种):当一个对象被创建之后,会立即调用构造方法,看下面这个例子,一般用于初始化数据
#encoding=utf-8
"""构造方法"""
class Structure:
def __init__(self,a,b,c):
print("对象被创建了..")
self.a=a
self.b = b
self.c = c
def add(self):
print(self.a+self.b+self.c)
structure=Structure("1","2","3")
structure.add()
b.重写一般方法和特殊的构造方法:
重写是继承机制中的一个重要内容,对于构造方法尤其重要,构造方法用来初始化新创建对象的状态,大多数子类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码,虽然重写的机制对于所有的方法来说都是一样的,但是当处理构造方法比重写方法时,也可能遇到特别的问题,比如,一个类的构造方法被重写那么就需要调用超类(你所继承的类)的构造方法,否则对象可能不会被正确的初始化。
"""重写一般方法"""
class A:
def hello(self):
print("hello I am A")
class B(A):
def hello(self):
print("hell I am B")
a=A()
b=B()
a.hello()
b.hello()
下面我们一起来看一下重写构造方法
"""重写构造方法"""
class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print("Asssh...")
self.hungry=False
else:
print("No ,Thanks")
#这个类定义了鸟都具有一些最基本的能力,吃,但是吃了之后,他就不在饥饿,
b=Bird()
b.eat()#输出Asssh... hungry值变成false
b.eat()#输出No ,Thanks
class SongBird(Bird):
#重写了构造方法
def __init__(self):
self.sound='Squawk!'
def sing(self):
print(self.sound)
sb=SongBird()
sb.sing()
#调用父类中的.eat方法会出现报错AttributeError: SongBird instance has no attribute 'hungry'
sb.eat()
很明显当我们运行程序的时候,sb.eat()报错了提示AttributeError: SongBird instance has no attribute 'hungry',原因很简单,在SongBrid中构造方法被重写了但是呢,新的构造方法并没有任何关于初始化hungry的特性代码,所以程序就报错了,为了解决这个问题,我们可以使用下面二种方法,第一种:调用超类构造方法的未绑定版本(很多遗留代码用到,可以好好了解,绑定和未绑定方法之间区别),第二种:使用super函数(推荐使用这种,简单明了)。
第一种:调用超类构造方法的未绑定版本:只需要在子类加上一句Bird.__init__(self)
class SongBird(Bird):
#重写了构造方法
def __init__(self):
"""self必须要加"""
Bird.__init__(self)
self.sound='Squawk!'
def sing(self):
print(self.sound)
这里解释一下,在调用一个实例的方法时,该方法的self参数会被自动绑定到实例(这个叫做绑定方法)前面已经给出了几个类似的例子了,但是如果直接调用类的方法(比如Bird.__init__),那么就没有被实例所绑定,这就是可以自由的提供需要的self参数,这样的方法成为“未绑定”方法,也就是我们本次使用的,而本次我们通过当前的实例作为self参数提供给未绑定方法,songBird就能够使用超类的构造方法的所有实现,也就是我们的hungry能够被设置
第二种:使用super函数
首先在Bird类前面加一句:
__metaclass__ = type #super()函数只在新式类中起作用,没有这个会报错
之后在类中
class SongBird(Bird):
#重写了构造方法
def __init__(self):
"""super()"""
#前面需要申明为新式类
super(SongBird,self).__init__()
self.sound='Squawk!'
def sing(self):
print(self.sound)
好了,在介绍一下super函数,对于super函数笔在超类中直接调用未绑定的方法更加直观,但是这个并不是他唯一的有点,实际上这个函数很只能,因此即使某个类继承多个超类,他也只需要使用一次super()函数(但是 需要确保所有的超类构造方法都使用了super()函数)
c.基本的序列和映射规则,序列和映射是对象的集合,为了实现他们的基本行为(规则)如果对象是不可变的,那么就需要使用二个魔法方法,如果是可变的则需要使用4个
**__len__(self) :这个方法应该返回集合中所包含项目的数量,对于序列来说,这就是元素的个数,对于映射来说,则是键-值的数量,如果__len__(self)返回0(并且没有实现重写元素该行文的__nonzero__),对象会被当做一个布尔变量中的假值(空的列表,元组,字符串和字典也一样)进行处理
**__getitem__(self,key) :这个方法返回所给健对应的值,对于每一个序列,健应该是一个0~n-1的整数(或者负数),n是序列的长度,对于映射来说,可以使用任何种类的健
** __setitem__(self,key,value):这个方法应该按一定的方式储存和key相关的value,该值随后可以使用__getitem__来获取,当然,只能为可以修改的对象定义这个方法
** __delitem__(self,key):这个方法在对一部分对象使用del语句时被调用,同时必须删除元素相关的健,这个方法也是为可修改的对象定义的(并不是删除全部的对象,而只是删除一些需要移除的元素)
** 对于一个序列来说,如果健是负整数,那么要从末尾开始计数,换句话说就是x[-n]和x[len(x)-n]是一样的
** 如果健是不合适的类型(例如,对序列使用字符串作为健)那么会引发一个typeError异常
** 如果序列的索引是正确的索引,但是超过了范围,应该引发一个IndexError的异常
下面是序列和映射的一个小例子
class AritmeticSequence:
def __init__(self,start=0,step=1):
self.start=start#保存开始值
self.step=step#保存步长值
self.changed={}#没有项被修改
def __getitem__(self, key):
chekIdex(key)
try:return self.changed[key]
except KeyError:
return self.start+key*self.step
def __setitem__(self, key, value):
"""修改某一个项目"""
chekIdex(key)
self.changed[key]=value
s = AritmeticSequence(1,10)
#获取无穷序列中的第二个的值 有下面二种方式
print(s.__getitem__(1))
print(s[1])
#修改无穷序列中key对应的值 有下面二种方式
s.__setitem__(1,3)#将key=1的 值修改成3
print(s.__getitem__(1))
s[1]=11#将key=1的 值改成11
print(s.__getitem__(1))
二、子类化列表,字典和字符串
当子类化一个内建类型,比如list的时候,也就间接的将object子类化了,因为这个类就自动成为新式类,这就意味着可以像super函数这样的特性了
举个例子
class Counterlist(list):
def __init__(self,*args):
super(Counterlist,self).__init__(*args)
self.counter=0
def __getitem__(self, index):
self.counter=self.counter+1
return super(Counterlist,self).__getitem__(index)
mylist=Counterlist(range(10))
print(mylist)
print(mylist.reverse())#按照从小到大排序[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(mylist)
del mylist[3:6]#删除3,4,5,6
print(mylist)
print(mylist.counter)#为0
print(mylist[4]+mylist[2])#这里mylist[4]第五个元素
print(mylist.counter)#定义了一个counter 当访问一次列表的时候 就会增加一次,上面访问了二次所以counter变成了2
在这个例子里面,定义的这个类严重依赖他的超类(list)的行为,但是并没有重写任何方法,只是初始化了counter,具体用法以后在介绍(暂时自己也不是很理解这种东西)
三、property函数 简单明了 ,看下面这个例子
__metaclass__=type#子类化object 标记为新式类
class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height = size
def getSize(self):
return self.width,self.height
#使用property创建一个属性,其中访问器函数名 被作为参数(先取值,在赋值),这个属性叫size
size=property(getSize,setSize)
r=Rectangle()
r.width=10
r.height=5
print(r.size)
r.size=150,100
print(r.width)
在这个例子中,开头加一个标记新式的语句,之后参数名,使用函数名,很明显,size特性仍然取决于getsize和setsize中的计算,但是他们看起来就像普通的属性一样。
注意:如果属性的行为很奇怪,那么要确保你所使用的类为新式类(通过直接或间接子类化
object,或直接设置元类);如如果不是的话,虽然属性的取值部分还是可以工作,但贼值部分就不一定了(取决python的版本:没关系我也不懂,先放在这里吧)
实际上,property函數可以用0、1、3或者4个参数来调用。如果没有参数,产生的属性既不
可读,也不可写。如果只使用一个参数调用(一个取值方法),产生的属性是只读的。第3个参数
(可选)是一个用于删除特性的方法(它不要参数)。第4个参数(可选)是一个文档字符串.Property
的4个参数分别被叫做fget、fset、 fde1和doc, 如果想要个属性是只写的, 并且有一个文档子
符串,可以使用关键字参数的方式来实现。
这里只是对property函数的简单说明, 但它却十分的重要。理论上说,在新式类中应该使用property函数而不是访问器方法。
四、模块
1、首先了解一下模块,当我们需要追加到sys.path中可以这样(临时增加)
import sys,pprint
pprint(sys.path) #查看path路径有多少
sys.path.append("C:/python")#py 文件不能有语法错误
之后我们使用的时候,将我们的Py文件/类,放到这个路径下面,我们就可以导入这个模块了,比如在c:/python,下面新建一个hello.py文件
#hello2.py
def hello():
print("hello2 you !")
之后我们在控制台/pycharm中(先引用sys),就可以直接import hello 这个模块了(hello.hello()调用里面的方法)
当然我们这样做的目的是因为,代码重用。。。。
2、我们现在了解一下,如何“告知”模块是作为程序运行还是导入到其他程序,我们需要引用__name__关键字,
首先我们可以打印一下print(__name__)发现输出值是__main__(我理解的是主程序)
所以我们在hello2.py中 重写代码为
#hello2.py
def hello():
print("hello2 you !")
def test():
hello()
if __name__ == '__main__':
test()
当然这个程序很简单,就是这个程序的__name__==如果是主程序的时候,就运行test(),假设是被人引入,那么就不运行。。。
五、包:
为了组织好模块,你可以将他们分成包,包实际上就是一类模块,但是为了标记Python会将其作为包对待,我们必须包含一个命名为__init__.py的文件(模块),如果将它作为普通模块导入的化,文件的内容 就是包的内容(默认会执行__init__.py中的代码)
import python_study#这个语句只能引用__init__中的内容
import python_study.SysPathStudy #这个语句引用python_study包中SysPathStudy模块,也可以用下面那个方式引用
# from python_study import SysPathStudy
python_study.xiejiangpeng()
python_study.SysPathStudy.xiejiangpeng()