Python基础(二)

有关于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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值