首页 > 技术文章 > python面向对象的三大特性继承 多态 封装

yuan-x 2020-01-18 12:28 原文

1 继承 

    python的继承分为单继承和多继承,新建的类被成为派生类或者子类,而继承的类被成为父类或者超类

   查看继承关系

使用__bases__方法查看所有继承对象------》  对象.__bases__
如果没有指定继承父类,则python3中则默认所有的类都继承object类,也叫新式类。

    继承与抽象的关系

       一定是将对象中的类似的内容抽象出来,在进行继承

    软件的重用

       如果我们在开发过程中,需要写一个新类,而这个类的功能和已存在的类功能相似,那么就可以通过继承,获得部分的功能,减少代码量

       同样的标准库或者第三方库同样可以被继承

    派生

         新类中也可以有自己的属性和方法,其中属性成为派生属性,方法成为派生方法。但是在定义的时候,要注意尽量别和父类的属性名和方法名重复,因为在调用的时候,如果新类中有,就回优先使用自己的而不去找父类的。

         如果新类中的方法需要用到父类中同名的方法,则可以使用类名.方法名()方法名直接调用,也可以使用supper()方法直接调用

        

# class animal:
#     def __init__(self,name,aggr,hp):
#         self.name=name
#         self.aggr=aggr
#         self.hp=hp
#
#     def eat(self):
#         self.hp+=100
# class dog(animal):
#     def __init__(self,name,aggr,hp,kind):
#         animal.__init__(self,name,aggr,hp)# 这里的self 是dog的self
#         self.kind=kind                         #派生属性  在父类的基础之上又派生了新的属性
#     def bite(self,person):                     #派生方法  在父类的基础上有派生了新的方法
#         person.hp-=self.aggr
#
#     def eat(self):
#         """
#         如果迹象实现新的功能也想使用父类原本的功能,还需要在子类中在掉用父类
#         :return:
#         """
#         animal.eat(self)# 这里的self是dog  作为参数传给了animal.eat
#         self.teeth = 2
# class person(animal):
#     def __init__(self,name,aggr,hp,sex):
#         animal.__init__(self,name,aggr,hp)
#         self.money=0
#         self.sex=sex
#
#     def attack(self,dog):
#         dog.hp-=self.aggr
#
#     def get_weson(self,weson):
#         pass
#
# jin=dog('二哈',100,500,'哈士奇')
# jin.eat()
# print(jin.hp)
# dan=person('dandan',20,100,'baobao')
# dan.eat()
# print(dan.hp)
# jin.bite(dan)
# print(dan.hp)

  super()用法

class animal:
    def __init__(self,name,aggr,hp):
        self.name=name
        self.aggr=aggr
        self.hp=hp

    def eat(self):
        self.hp+=100
        print('吃药回血')

class dog(animal):
    def __init__(self,name,aggr,hp,kind):
        #super(dog,self).__init__(name,aggr,hp)  supper内参数可以不传
        super().__init__(name, aggr, hp)
        self.kind=kind
    def eat(self):
        print('dog eating')


jin=dog('二哈',200,100,'哈士奇')
print(jin.name)
jin.eat()
super(dog,jin).eat()   #如果是在类外 使用supper(类名,实例化名).方法()   就会执行类中的方法

  python中的抽象类和接口类:

           python原生不支持接口类,接口类是java的概念,在python中可以将接口类看成抽象类。抽象类无法被实例化

                ,且内部方法不能被实现。抽象类和接口类更像是一种类的规范。

           python中的继承包括两种用途:

                  1 继承父类的方法,并且有自己改变或者扩展(派生)

                   2 声明某个子类兼容与某父类,就是定义一个接口类interface,接口类中定义了一些接口名但 是未能实现,子类继承接口类,必须要实现继承的接口类中的方法。

             在实际工作中,继承的第一种用法含义并不大,因为它是的子类与父类穿线强耦合

               第二种比较重要,叫着接口的继承。接口继承实际上要求做出一个良好的抽象,这个抽象规定了一个兼容接口,是的外部调用者无序关心具体袭击,可以一视同仁的处理实现了特定接口的所有对象--这种程序上的设计叫做归一化。类似与linux的泛文件概念。

# from abc import abstractclassmethod,ABCMeta
# class Payment(metaclass=ABCMeta):#   元类 默认的元类 type  这里指定元类为ABCmeta 规范一个类
#     @abstractclassmethod
#     def pay(self,money):
#         pass
# # class Payment1:
# #     def pay1(self):
# #         raise NotImplemented #没有实现这个方法,也就是子类中没有实现父类的方法就会主动抛出异常
# class Wechat(Payment):
#     def pay(self,money):
#         print('已经使用微信支出%s',money)
# class alichat(Payment):
#     def pay(self,money):
#         print('已经使用ali支出%s',money)
# class appchat(Payment):
#     def pay1(self,money):
#         print('已经使用app支出%s',money)
# def pay(pay_obj,money):    #统一支付接口
#     pay_obj.pay(money)
# we=Wechat()
# app=appchat()
# pay(we,199)
# pay(app,300)

  接口类的继承:

# from abc import abstractclassmethod,ABCMeta
# class swim_animal(metaclass=ABCMeta):
#     @abstractclassmethod
#     def swim(self):
#         pass
#
# class walk_animal(metaclass=ABCMeta):
#     @abstractclassmethod
#     def walk(self):
#         pass
#
# class fly_animal(metaclass=ABCMeta):
#     @abstractclassmethod
#     def fly(self):
#         pass
#
# class tiger(swim_animal,walk_animal,fly_animal):
#     def swim(self):
#         print('tiger swim')
#     def walk(self):
#         print('tiger swim')
#     def fly(self):
#         print('tiger swim')

  python中利用abc模块实现抽象类:在py3.4之后,@abc.abstractclassmethod被弃用,所以pycharm会在该装饰器函数上画一条横线

import abc #利用abc模块实现抽象类
class all_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractclassmethod
    def read(self):#定义抽象方法,无需实现功能,当然也可以实现部分功能
        '子类必须定义读功能'
        print('all_file read')
        pass
    @abc.abstractclassmethod
    def write(self):
        '子类必须定义写功能'
        pass

class txt(all_file):
    def read(self):
        print('txt read')
    def write(self):
        print('txt write')

t1=txt()
t1.read()
t1.write()
print(t1.all_type)

  继承的顺序:

                  1 python中的类可以继承多个类,java和c#只能继承一个类

                   2 python中的类如果继承了多个类,那么其寻找方法的方式有两种,分别是广度优先和深度优先。如果是经典类,多继承下是深度优先,如果是新式类多继承下是广度优先,在python中都是新式类。

                    原理:

                            如果你定义一个类,python会计算出一个方法解析顺序mro列表,这个mro列表即使一个简单的所有父类的线性顺序列表

                            父类的mro列表回遵循如下三条准则

                                  1 子类会先于父类被检查,如果子类和父类中有相同的方法名的时候 要特别注意。

                                   2 多个父类会根据它们在列表中的顺序被检查

                                   3 如果对下一个类存在两个合法的选择,选择第一个父类

 

多态        

          python中天生支持多态。一种事物有多种形态,强类型语言需要定义参数类型,python是动态强类型语言,比如2+str=2str 但python中会报类型错误

          百度中的概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

  

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()

  

 

封装:

           代码的保护,面向对象的思想本身就是一种封装,只让自己的对象调用自己类中的方法。就是将属性和方法都藏起来。

           

类的私有:
所有的私有,都是在变量的左边加上双下划线
1 对象的私有属性
2 类中的私有方法
3 类中的静态私有属性
所有的私有,都不能在类的外部使用

          

#类的私有属性  只是在代码层面不允许用 对象.属性的方式调用
# class userinfo:
#     __key=123  #私有的静态属性
#     def __init__(self,name,pwd):
#         self.name=name
#         self.__pwd=pwd   #私有属性
#     def get_pwd(self):
#         # 只要在类的内部使用私有属性,就会自动带上  _类名
#         # 注意如果此时在类的外部调用pwd 需要用 _userinfo__pwd
#         # 这一点可以通过在外部定义一个 带下划线的方法来实验例如  yuan._pwd1
#         # 这样在外部依然可以用 yuan._pwd1来调用该方法
#         print('get_pwd--》',self.__dict__)
#         return self.__pwd
#
#     def __user_name(self):
#         #私有的方法  只在内部使用 外部没办法感知
#         print(self.__dict__)
#         print('__user_name')
#     def use(self):
#         print('use',self.__dict__)
#         self.__user_name()
# yuan=userinfo('dandan',123456)
# print(yuan.name)
#
# #print(yuan.__pwd)  会报错
# print(yuan.__dict__)  查看self之后看到对象中没有__pwd,所以需要yuan._userinfo__pwd的方式调用
# print(yuan._userinfo__pwd)    #_类名__属性
# yuan._weight=100  #设定对象的隐藏方法
# print(yuan._weight)
# print(yuan.use())


#假设父类的私有属性,能被子类调用??
class foo:
    __y='212'
class son(foo):
    #print(foo.__key)
     pass
#弱项调用必须在外部调用需要以下列方式
# print(son._foo__y)

  property  classmethod staicmethod用法:

'''

遗留的内置函数
            property
            classmethod
            staticmethod
'''
#property   内置装饰器函数,只在面向对象中使用
#被property装饰的方法不能传任何参数
# 只是使类中的方法看起来更像是一个属性,
# 在类的外部调用该方法的时候,不用加()调用
from math import pi

# class circle:
#     def __init__(self,r):
#         self.r=r
#     @property
#     def perimeter(self):
#         return 2*pi*self.r
#     @property
#     def area(self):
#         return pow(self.r,2)*pi
#
# c1=circle(6)
# print(c1.perimeter)
# print(c1.area)

# class person:
#     def __init__(self,name,high,weight):
#         self.name=name
#         self.high=high
#         self.weight=weight
#     @property
#     def bmi(self):
#         return self.weight/self.high**2
#     @property
#     def fab_bmi(self):
#         return 22*pow(self.high,2)
#
# yuan=person('袁',1.74,91)
# print(yuan.bmi)
# print(yuan.fab_bmi)

#利用property 修改类的私有属性
#property 可以看成将方法置成了一个类的属性 在外部是不能被更改的
#需要配合 @被property装饰的函数同名.setter 在定义一个新的和被property装饰的方法同名的方法才能完成修改
#所以如果想使用    @被property装饰的函数同名.setter 更改则必须先使用@property
# class edit_name:
#     def __init__(self,name):
#         self.__name=name
#     @property
#     def name1(self):
#         return self.__name+'sb'
#
#     @name1.setter
#     def name1(self,new_name):
#         print('name1 edit')
#         self.__name=new_name
#
# cat=edit_name('dandan')
# print(cat.name1)
# cat.name1='wangyongmei'
# print(cat.name1)


# class goods:
#     discount=0.8
#     def __init__(self,name,price):
#         self.name=name
#         self.__price=price
#     @property
#     def price(self):
#         return self.__price*goods.discount
# app=goods('玉米',6)
# print(app.price)

#属性的删除 修改 查看
# class del_name:
#     def __init__(self,name):
#         self.__name=name
#     @property
#     def name1(self):
#         return self.__name
#     @name1.deleter
#     def name1(self):
#         print('执行了这个方法')
#         del self.__name
#     @name1.setter
#     def name1(self,newname):
#         self.__name=newname
#
# del_oldname=del_name('niu')
# print(del_oldname.name1)
# print(del_oldname.__dict__)
#
# #del 只是触发了类中 @被property装饰的函数同名.deleter 装饰的方法
# del del_oldname.name1
# print(del_oldname.__dict__)
# #print(del_oldname.name1)



'''

method 方法
       staticmethod 静态的方法
       classmethod  类方法 
                    把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
                    当这个方法的操作只设计静态属性的时候,就应该使用classmethod来装饰这个方法

'''
# class goods:
#     __discount=0.8
#     def __init__(self,name,price):
#         self.name=name
#         self.__price=price
#     @property
#     def price(self):
#         return self.__price*goods.__discount
#     @classmethod  #把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
#     def change_discont(cls,newdiscont):
#         cls.__discount=newdiscont
#
# app=goods('玉米',6)
# print(app.price)
# goods.change_discont(0.6)
# print(app.price)


#面向对象编程  staticmethod 方法
class Login:
    def __init__(self,name,password):
        self.name=name
        self.password=password
    def login(self):
        pass
    @staticmethod
    def get_user():
        user=input('usename')
        pwd=input('pwd')
        Login(user,pwd)

Login.get_user()

#在完全面向对象的程序中
#如果一个函数,既和对象没有关系,也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法
#类方法,有一个默认参数cls,代表这个类cls
#静态方法 没有默认的参数,就像函数一样

  反射  hasattr getattr deattr:

'''

反射

hasattr getattr deattr
'''

class teacher:
    dic={'查看学生信息':'show_student','查看讲师信息':'show_teacher'}
    @classmethod
    def show_student(cls):
        print('show_student')
    @classmethod
    def show_teacher(self):
        print('show_teacher')

    @classmethod
    def func(cls):
        print('sdf')

# ret=getattr(teacher,'dic')    #teacher.dic  类也是对象,需要注意的是被调用的函数是实例函数还是类函数,如果是实例函数则需要实例化类-->
# print(ret)
# ret01=getattr(teacher,'func')  #teacher.func()
# ret01()
# if hasattr(teacher,'show_student'):
#     ret02=getattr(teacher,'show_student')
#     print(ret02)
#     ret02()
#
#
# yuan=teacher()
# ret03=getattr(yuan,'show_teacher')
# ret03()
for k in teacher.dic:
    print(k)
key_info=input("pelase select info")
if hasattr(teacher,key_info):
    ret7=getattr(teacher,teacher.dic[key_info])
    ret7()

'''
通过反射
对象名 获取对象属性和普通方法
类名 获取静态属性和类方法和静态方法


1 同样,若不想正常调用模块中的方法,可以采用反射
2 内置模块也能用
import time
# time.asctime()
ret9=getattr(time,'asctime')
print(ret9())
'''
 3 反射自己模块中的变量
# import sys
# def cap():
#     print('反射自己模块中变量')
#     return '反射自己模块中变量01'
# year=2018
# ret4=getattr(sys.modules['__main__'],'year')
# print(ret4)
# #反射自己模块中的函数
# ret5=getattr(sys.modules['__main__'],'cap')
# print(ret5())

  

  类的内置方法:

'''

类的内置方法
    类的内置方法 和 内置函数之间有着千丝万缕的联系
双下方法
   __str__
         object 里边有个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
         __str__返回的一定是个字符串
   __repr__


   %s str() 直接打印 实际上执行的是 __str__
   %r repr() 实际上是__repr__
   repr是str的备胎,但是str不能做repr的备胎
   str(obj) 实际上是内部调用了obj.__str__方法,如果str方法有,那么它必须返回一个字符串
   如果没有__str__方法,回系按照本类 __repr__方法,再没有再找父类中的__str__
   repr() 只会找__repr__ 如果没有找父类的
'''

# class a:
#     def __str__(self):
#         return 'a'
#
# a1=a()
# print(a1) #打印一个对象的时候,就是调用a.__str__
# #a1.__str__ ---》object
# #object 里里边有个__str__ 一旦被调用,就返回调用这个方法的对象的内存地址
#
# l=[1,2,3,4]  #实例化了一个列表对象
# print(l)  #---->实际上 调用了 __str__

# class teacher:
#     def __init__(self,name,salary):
#         self.name=name
#         self.salary=salary
#     def __str__(self):
#         return 'teacher object :%s'%self.name
#
#     def __repr__(self):
#         return str(self.__dict__)
#     def func(self):
#         return 'dddddd'
#
# wukong=teacher('aoteman',252)
# print(str(wukong))
# print(repr(wukong))
# print('%r'%wukong) #自己有__repr__ 就用自己的 如果没有 就调用父类的object


# class cla:
#     def __init__(self,name):
#         self.name=name
#         self.studen=[]
#     def __len__(self):
#         print('len1')
#         # 这个地方self.studen不是实例化对象所以不会调用自己的双下len方法,
#         # 但是如果写成len(self)就回默认调用自己的双下len方法,因为self指的是类的本身
#
#         # __len__方法是cla类的内置方法,根据继承可知,实例在调用方法的时候,会先调自己的
#         #所以在外部调用len(实例化对象) 会调自己的__len__方法
#         #但是在return的时候又了一次len方法,但是传入的是一个实例化的列表对象
#         #所以这个return的len实际上是调用list的__len__方法,list自己没有__len__方法,所以最终调用的还是object的
#         return len(self.studen)

# ps=cla('py9')
# ps.studen.append('dsf')
# ps.studen.append('dsf')
# print(len(ps))
#
# '''
# __del__ 析构函数
# 在删除一个对象之前,进行一些收尾工作
'''
# class af:
#     def __del__(self):  #析构函数 在删除一个对象前进行一些收尾工作
#         self.f.close()
# a123=af()
# a123.f=open()  #打开文件1 在操作系统中打开一个文件 拿到文件操作符存在内存中
# del a123       #直接删除a123 等于也删除了a123.f拿到的了文件操作符,但是此时系统中的文件并没有关闭
#引用计数 python的垃圾回收机制  如果检测到下边还有地方引用a123或者类 计数+1如果没有就制程0
# 
# '''
# __call__  一个对象加() 等于执行类内部的__call__方法
#
# '''

class yu:
    def __init__(self,name):
        self.name=name

    def __call__(self):
        print('内置call方法被执行')

a=yu('ni')()

 item __getiem__  __setitem__   __delitem__ 支持字典增删改查,查看字典源码,其实也是这样写的,包含列表,只是多了一种取值方法。

# class foo(object):
#     def __init__(self,name,age,sex):
#         self.name=name
#         self.age=age
#         self.sex=sex
#     def __getitem__(self, item):
#         if hasattr(self,item):
#             return self.__dict__[item]
#     def __setitem__(self, key, value):
#         self.__dict__[key]=value
#     def __delitem__(self, key):
#         del self.__dict__[key]
#
# f=foo('yuan',18,'man')
# print(f['name'])
# f['like']='son'
# print(f.like)                    #object原生支持
# print(f.like,f['like'])          #通过自己实现的
# print(f.__dict__)
# del f['like']
# print(f.__dict__)

  __init__ 初始化方法    __new__  创建一个对象。其实类的实例化时,是默认执行了object的__new__方法,用于构建一个self  

# class a:
#     def __init__(self):
#         self.x=1
#         print('init function')
#     def __new__(cls, *args, **kwargs):
#         print('__new__')
#         return object.__new__(a,*args,**kwargs) #这里class a并没有能实现构造的方法 所以还是需要调用object的
# b=a()

  单例模式  __new__   一个类始终只有一个实例,限制一个类从头到位只有一个实例,当你之后再来实例化的时候看就用之前创建的对象

#23种
#__new__   单例模式
#        一个类始终只有一个实例 限制一个类从头到尾只有一个实例
#        当你之后再来实例化的时候看就用之前创建的对象

# class b:
#     __insta=False
#     def __init__(self,name,age):
#         self.name=name
#         self.age=age
#     def __new__(cls, *args, **kwargs):
#         '''
#         在外部实例化该类的时候,回执行类中的双下new方法
#         通过判断_insta的真假,返回不同的返回值,在第一次
#         实例化该类的时候,其实通过在类的内部改变了私有__insta的方法
#         当下次再实例化调用时,就返回已经变更过的私有__insta方法
#
#         '''
#         if cls.__insta:
#             return cls.__insta
#         cls.__insta=object.__new__(b)
#         return cls.__insta
# egon=b('agg',38)
# nezha=b('nazha',25)
# print(nezha)
# print(egon)
# print(nezha.name)
# print(egon.name)

  __eq__  和 __hash__

# class f:
#     def __init__(self,name):
#         self.name=name
#
#     def __eq__(self, other):
#         if self.name==other.name:
#             return True
#         else:
#             return False
# yu1=f('yuan')
# yu2=f('yuan')
# print(yu1==yu2)




class h:
    def __init__(self,name,sex):
        self.name=name
        self.sex=sex
    def __hash__(self):
        return hash(self.name+self.sex)

h1=h('yu','man')
h2=h('yu','man')
print(hash(h1))
print(hash(h2))

     set 依赖__hash__  __eq__  

class hashs:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def __eq__(self, other):
        print(self,other)
        print('eq2222')
        if self.name==other.name and self.sex==other.sex:
            return True
        else:
            return False
    def __hash__(self):
        print('hash111')
        return hash(self.name+self.sex)

a=hashs('yuan',18,'man')
b=hashs('yuan',25,'man')

#set的实现 依赖对象hash eq方法 先调用hash 拿到hash值 在调用eq
print(set((a,b)))
hs=set((a,b))
print(hs)

  

 

 

其他的内置方法

类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

 类的组合

'''


面向对象的三大特性:  继承  多态 封装

类的组合:一个对象的属性值是另外一个类的对象
          w=weapon('粪叉子',100,3,200)
          yuanbao.get_weapon(w)    通过self  将武器对象绑定成自己的属性值
          yuanbao.weapon.hand18(jin)



'''
# class dog:
#     def __init__(self,name,aggr,hp,kind):
#         self.name=name
#         self.aggr=aggr
#         self.hp=hp
#         self.kind=kind
#     def bite(self,person):
#         person.hp-=self.aggr
#         print('%s被狗咬了,掉了%s滴血'%(person.name,self.aggr))
#
# class person:
#     def __init__(self,name,aggr,hp,sex):
#         self.name=name
#         self.aggr=aggr
#         self.hp=hp
#         self.sex=sex
#         self.money=0
#     def attack(self,dog):
#         dog.hp-=self.aggr
#         print('%s被人打了,掉了%s滴血'%(dog.name,self.aggr))
#     def get_weapon(self,weapon):
#         if self.money>weapon.price:
#             self.money-=weapon.price
#             self.aggr+=weapon.statck
#             self.weapon=weapon
#         else:
#             print('钱不够')
#
# class weapon:
#     def __init__(self,name,statck,lasting,price):
#         self.name=name
#         self.statck=statck
#         self.lasting=lasting
#         self.price=price
#     def hand18(self,person):
#         if self.lasting>0:
#             person.hp-=self.statck*2
#             self.lasting-=1
#
#
#
# yuanbao=person('蛋蛋',2,100,'未知')
#
# jin=dog('二哈',100,500,'teddy')
# w=weapon('粪叉子',100,3,200)
# #充钱
# yuanbao.money=1000
# print(yuanbao.__dict__)
# #装备打狗棒
# yuanbao.get_weapon(w)
# #打狗
# yuanbao.attack(jin)
# print(jin.hp)
#
# #使用打狗棒大招
# yuanbao.weapon.hand18(jin)
# print(jin.hp)


'''

类的组合  :
           一个对象的属性是另一类的对象
           实际上在A类中将B类的实例化赋值给变量S,然后通过调用的方式使用B中的属性 AA=A.S.func
圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。
这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用
'''


# from math import pi
#
# class roundness:
#     def __init__(self,r):
#         self.r=r
#     def permiter(self):
#         return pi*self.r*2
#     def areas(self):
#         return pi*pow(self.r,2)
#
#
# class annulus:
#     def __init__(self,outside_r,inside_r):
#         self.outs=roundness(outside_r)
#         self.inside=roundness(inside_r)
#
#
#     def annu_per(self):
#         return self.outs.permiter()+self.inside.permiter()
#     def annu_areas(self):
#         return abs(self.outs.areas()-self.inside.permiter())
#
# ring=annulus(30,20)
# print(ring.annu_areas())
# print(ring.annu_per())

class bir:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
class teacher:
    def __init__(self,name,age,sex,b):
        self.name=name
        self.age=age
        self.sex=sex
        self.b=b
birs=bir(2018,12,8)
t1=teacher('yu',18,'man',birs)
print(t1.name)
print(t1.b.year)

  

 

  

推荐阅读