python基础之多态与多继承

多态

多态使用

一种事物的多种体现形式,举例:动物有很多种

注意: 继承是多态的前提

函数重写就是多态的体现形式

演示:

思路:

第一步:先定义猫类和老鼠类,继承自object,在其中书写构造方法和eat方法

第二步: 抽取Animal父类,定义属性和eat方法,猫类与老鼠类继承即可

第三步: 定义人类,在其中分别定义喂猫和喂老鼠的方法

第四步:使用多态,将多个喂的方法提取一个

# 测试类
from cat import Cat
from mouse import Mouse
from person import Person
'''
多态: 一种事物的多种状态
需求:人可以喂任何一种动物
'''
#创建猫和老鼠的对象
tom = Cat("tom")
jerry = Mouse("jerry")

#调用各自的方法
tom.eat()
jerry.eat()

#思考:在添加100种动物,也都有name属性和eat方法--> 体现继承的好处
#定义了一个有name属性和eat方法的Animal类,让所有的动物类都继承自Animal.

#定义一个人类,可以喂猫和老鼠吃东西
per = Person()
#per.feedCat(tom)
#per.feedMouse(jerry)

#思考:人要喂100种动物,难道要写100个feed方法吗?
#前提:tom和jerry都继承自动物
per.feedAnimal(tom)
per.feedAnimal(jerry)
class  Animal(object):
    def __init__(self, name):
        self.name = name
    def eat(self):
        print(self.name + "吃")
#猫类
from animal import Animal
class Cat(Animal):
    def __init__(self, name):
        #self.name = name
        supper(Cat,self).__init__(name)
#老鼠类
from animal import Animal
class Mouse(Animal):
    def __init__(self, name):
        #self.name = name
        super(Mouse,self).__init__(name)
#人类
class Preson(oject):
    def feedAnim(self, ani)
        print("给你食物")
        ani.eat()

对象属性与类属性

对象属性和类属性的区别:

扫描二维码关注公众号,回复: 10508923 查看本文章

a.定义的位置不同,类属性是直接在类中的属性,对象属性是在定义在构造方法中的属性

b.对象属性使用对象访问,类属性使用类名访问

c.在内存中出现的时机不同[类属性随着类的加载而出现,对象属性随着对象的创建而出现]

d.优先级不同,对象属性的优先级高于类属性

class Person(object):
    #1.定义位置
    #类属性:直接定义在类中的属性
    name = "person"
    def __init__(self, name):
        #对象属性:定义在构造方法中的属性
        self.name = name
#2.访问方式
print(Person.name)
per = Person("tom")
#对象属性的优先级高于类属性
print(per.name)
#动态的给对象添加对象属性
per.age = 18
#只针对当前对象生效,对于类创建的其他对象没有作用
print(Person.name)
per2 = Person("lilei")
#print(per2.age) #没有age属性
#删除对象中的name属性,再调用会使用到同名的类属性
del per.name
print(per.name)

#注意事项:不要将对象属性与类属性重名,因为对象属性会屏蔽掉类属性,但是当删除对象属性之后,再使用就能使用到类属性了.

动态添加属性和方法

正常情况下,我们定义了一个class,创建一个class的实例后,我们可以给该实例绑定任何的的属性和方法,这就是动态语言的灵活性。

#python语言的特点:灵活
#这里说的动态加属性和方法主要指的是关于__slots__函数的使用
from types import MethodType

#定义一个空类
'''
class Person():
    pass
'''
class Person(object):
    __slots__ = ("name","age","speak","hobby")
# 动态添加属性[体现了动态语言的特点:灵活性]
per = Person()
per.name = "tom"
print(per.name)

#动态添加方法
def say(self):
    print("my name is "+ self.name)
per.speak = say
per.speak()
per.speak(per)
#这样实现不好,所以引入MethodType

但是,给一个实例绑定的方法对另外一个实例是不起作用的。

为了给所有的实例都绑定方法,可以通过给class绑定方法

#动态添加方法
def say(self,name):
    self.name = name
    print("my name is "+ self.name)
Person.speak = say

给class绑定方法后,所有的实例均可调用。

通常情况下,上面的say方法可以直接定义在class中,但动态绑定允许我们在程序在运行的过程中动态的给class添加功能,这在静态语言中很难实现。

如果我们想限制实例的属性怎么办?

比如,只允许给Person实例添加name,age属性,为了达到限制的目的,Python中允许在定义class的时候,定义一个特殊的变量【slots】变量,来限制该class添加的属性

class Person(object):
    __slots__=("name","age")
#[不想无限制的任意添加属性]
#比如,只允许给对象添加name, age属性
#解决:定义类的时候,定义一个特殊的属性(__slots__),可以限制动态添加的属性范围
per.height = 170
print(per.height)

使用slots的时候需要注意,slots定义的属性仅仅对当前类的实例起作用,对继承的子类是不起作用的。

除非在子类中也定义slots,这样子类实例允许定义的属性就是自身的slots加上父类的slots

@property

绑定属性时,如果我们直接把属性暴露出去,虽然写起来简单,但是没有办法检查参数,导致可以随意的更改年龄。

p = Person()
p.age = -1

这显然不合常理,为了限制age的范围,我们可以通过setAge()的方法来设置age,再通过getAge()的方法获取age,这样在setAge()中就可以检查参数。

class Person(object):
    def __init__(self, name, age):
        #属性直接对外暴露
        #self.age = age
        #限制访问
        self.__age = age
        #self.__name = name

     def getAge(self):
        return self.__age
     def setAge(self, age):
        if age < 0:
            age = 0
        self.__age = age
    #通过@property和@age.setter改变原来的get/set方法
    #方法名为受限制的变量去掉双下划线
    #相当于get方法
    @property
    def age(self):
        return self.__age
    #相当于set的方法
    @age.setter #去掉下划线.setter
    def age(self, age):
        if age < 0:
            age = 0
        self.__age = age

    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self, name):
        self.__name = name
 per = Person("lili",18)
#属性直接对外暴露
#不安全,没有数据的过滤
#per.age = -10
#print(per.age)

#使用限制访问,需要自己写set和get的方法才能访问
#劣势:麻烦,代码不直观
#思考问题:如果我就想使用对象.的方式访问对象的私有属性,怎么办?
#per.setAge(15)
#print(per.getAge())

#property:可以让你对受限制访问的属性使用点语法
per.age = 80 #相当于调用setAge
print(per.age)#相当于调用getAge

print(per.name)

总结:

a.装饰器(decorator)可以给函数动态加上功能,对于类的方法,装饰器一样起作用,python内置的@property装饰器就是负责把一个方法变成属性调用的

b.@property的实现比较复杂,我们先考察如何使用,把一个getter方法变成属性,只需要加上@property就可以了,此时@property本身又创建了另一个装饰器@属性.setter,负责把一个setter方法变成属性赋值.

c.@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性

运算符重载

类可以重载加减运算,打印,函数调用,索引等内置运算,运算符重载使我们的对象的行为与内置函数一样,在python调用时操作符会自动的作用于类的对象,python会自动的搜索并调用对象中指定的方法完成操作。

常见的运算符重载方法

![06BCCAA-9E53-41A0-83F0-8FBA90A215F](/Users/zhangjiao/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/1838887021/QQ/Temp.db/F06BCCAA-9E53-41A0-83F0-8FBA90A215F6.png)

举例

#举例
#数字和字符串都能相加
print(1 + 2)
print("1" + "2")
#不同的类型用加法会有不同的解释

class Person(object):
    def __init__(self, num):
        self.num = num
     #运算符重载   
    def __add__(self, other):
        return Person(self.num + other.num)

    #方法重写
    def __str__(self):
        return "num = " + str(self.num)

#如果两个对象相加会怎样?
#对象相加,编译器解释不了,所以就要用到运算符重载
per1 = Person(1)
per2 = Person(2)
print(per1 + per2)
#结果为地址:per1+per2 === per1.__add__(per2),如果想得到num和则重写str方法
#上述打印就等价于:print(per1.__add__(per2)),只不过add方法会自动调用
print(per1)
print(per2)       

发送短信和邮件

前提:互亿无线账号[上海] 和163邮箱

APIID:C96007594
APIKEY:63dddb423532e74c755637ff759042e2


# SMTP服务器

SMTPServer = "smtp.163.com"

# 发邮件的地址

sender = "[email protected]"
发短息

登录成功之后,互亿无限==>验证码短信==>获取APIID和APIKEY

==>文档中心 ==> 短信验证码/短信通知API接口文档下载,获取到接口文档 ==> 打开文档demo下的python[注意:最好先用记事本打开,复制到pyCharm中]

对原代码的修改如下:

代码如下:

#接口类型:互亿无限触发短信接口,支持发送验证码短信,订单通知短信等.
#账户注册:请通过该地址开通账户
http://sms.ihuyi.com/register.html
#注意事项:
#1.调用期间,请用默认的模板进行测试,默认模板详见接口文档
#2.请使用APIID(查看APIID请登录用户中心-->验证码短信-->产品总览-->APPID)及APIKEY来调用接口.
#3.该代码仅提供接入互亿无线短信接口参考使用,客户可以根据实际需要进行自行编写.
#!/user/local/bin/python
#_*_ coding:utf-8 _*_
import http.client
import urllib

host = "106.ihuiyi.com"
sms_send_uri = "/webservice/sms.php?method=Submit"

#用户名是登录用户中心-->验证码短信 -->产品总览 -->APPID
account = "C96009595"
#密码 查看密码请登录用户中心 --> 验证码短信 --> 产品总览 -->APIKEY

password ="63dddb423532e74c755637ff759042e2"
def send_sms(text,mobile):
    params = urllib.parse.urlencode({'account':account,'password':password,'content':text,'mobile':mobile,'format':'json'})
    headers = {"Content-type":"application/x-www-form-urlencoded", "Accept":"text/plain"}
    conn = http.client.HTTPConnection(host, port=80, timeout=30)
    conn.request("POST", sms_send_uri, params, headers)
    response = conn.getresponse()
    response_str = response.read()
    conn.close()
    return response_str
if __name__ == "__main__":
    moblie = "18388878901"
    text ="您的验证码是: 908078. 请不要把验证码泄露给其他人."
    print(send_sms(text, mobile))

发邮件

登录163邮箱 —> 设置 —>POP3/SMTP/IMAP —>客户端授权密码 —>开启 —> 重置授权码

注意: 授权码尽量和邮件的登录密码不同[],将下面的password改为授权码

#发邮件的库
import smtplib
#邮件文本
from email.mime.text import MIMEText

#STMP服务器
SMTPServer = "smtp.163.com"
#发邮件的地址
sender = "[email protected]"
#发送者邮箱的密码:授权码
password = "1q2w3e"
#设置发送的内容
message = "hello"
#转换成邮件文本
msg = MIMEText(message)
#标题
msg["Subject"] = "来自星星的我"
#发送者
msg["From"] = sender
#收件人
msg["To"] = "[email protected]"

#创建SMTP服务器,端口号一般为25
mailServer = smtplib.SMTP(SMTPServer,25)
#登录邮箱
mailServer.login(sender, password)
#发送邮件
mailServer.sendmail(sender, ["[email protected]"],msg.as_string())
#退出邮箱
mailServer.quit()
发布了31 篇原创文章 · 获赞 4 · 访问量 3514

猜你喜欢

转载自blog.csdn.net/qq_29074261/article/details/80016830
今日推荐