第十四天python3 面向对象

1、面向对象
是对现实世界中的事物进行抽象的方式;

一切皆对象;
    对象是数据和操作的封装;
    对象之间相互独立,但也可以相互作用;
  三要素:
    封装:
      数据与方法的集合;
      提供一个或者多个接口来访问;隐藏数据,使用者不需要知道具体是怎么运作的;
    继承:多继承,少修改,继承来的就不用自己写了;
    多态:动态绑定;
2、类
类是一系列事物的统称,同类事物必定具有相同的特征;对应到类中是变量和方法;

定义类的语法格式:
class Cat:
    pass

3、对象
对象是类的具体表现形式;是实际存在的个体;

#定义类
class Cat:
    print("Hello Word")

#创建对象,也叫实例化对象
cat1=Cat()

4、成员变量
用于描述对象的固有状态或属性

class 类名:
    def __init__(self):
        self.变量名1 = 值1
        self.变量名2 = 值2

5、成员方法
用于描述对象的固有行为;

class 类名:
    def __init__(self):
        self.变量名1 = "值1"
        self.变量名2 = "值2"
    
    def 方法名1(self):
        方法体
    def 方法名2(self):
        方法体

调用方法格式:
    对象名.方法名()

#######################################

class MyClass:
    """A example class"""
    x = 'abc'
    def foo(self):
        return 'My Class'

#MyClass这个类调用共有属性
print(MyClass.x)
abc

#返回内存中函数对象的地址
print(MyClass.foo)
<function MyClass.foo at 0x0000020F73459F70>

#没有被实例化而调用foo方法,提示foo()需要一个参数
print(MyClass.foo())
Traceback (most recent call last):
  File "d:/Doc/test.py", line 7, in <module>
    print(MyClass.foo())
TypeError: foo() missing 1 required positional argument: 'self'

#MyClass实例化后调用foo()方法;self指代当前实例本身,在这个示例中self表示的就是MyClass();
#可以这理解,当MyClass()实例调用foo()方法的时候,self=MyClass(),也就是foo(MyClass())
print(MyClass().foo())
My Class

#__doc__也是类的属性
print(MyClass.__doc__)
A example class

#每实例化出一个对象,都可以和方法做绑定,也就是说多个对象可以绑定一个方法;他们在内存中的地址是不一样的;
a = MyClass()
print(MyClass().foo)
print(a.foo)
print(hex(id(a.foo)))
<bound method MyClass.foo of <__main__.MyClass object at 0x000001C3E93A5C40>>
<bound method MyClass.foo of <__main__.MyClass object at 0x000001C3E9376B50>>
0x1c3e8ed3100

#一个是通过实例访问,一个是通过类访问;
print(a.foo)  #MyClass类对象的内存地址
print(MyClass.foo)  #函数对象的内存地址
<bound method MyClass.foo of <__main__.MyClass object at 0x00000246CBD86B50>>
<function MyClass.foo at 0x00000246CBDC9F70>
#前后都有下划线的方法称为魔术方法,init可以理解为初始化方法,当构建一个实例的时候都会去执行这个方法
class Persion:
    def __init__(self,name):
        print(name)
        
p = Persion()
print(p)
TypeError: __init__() missing 1 required positional argument: 'name'

p1 = Persion('tom')
print(p1)
tom
<__main__.Persion object at 0x000002152D9E5C40>

#############################

面向对象代码执行过程:

class Horse:
    nose="鼻子"
    eye="眼睛"
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def showname(self):
        print('{} is {} 有 {} 有 {}'.format(self.name,self.age,self.nose,self.eye))

whitehorse = Horse('whitehorse',18)
darkhorse = Horse('darkhorse',19)

whitehorse.showname()
darkhorse.showname()
print(darkhorse.age)
darkhorse.age += 1
print(darkhorse.age)
'''
执行结果:
whitehorse is 18 有 鼻子 有 眼睛
darkhorse is 19 有 鼻子 有 眼睛 
19
20
'''

  1、首先在内存中定义一个Horse的类对象,在这个类对象中捆绑一个__init__的属性,生成一个归类对象Horse管理的函数;
  2、对Horse这个类做实例化操作,创建两个实例,whitehorse和darkhorse;执行__init__函数,与创建的实例建立关系;
  3、whitehorse/darkhorse再去调用showname方法,showname方法再调用实例变量和类变量打印结果;

实例化
  baima = Horse('baima','18')
  heima = Horse('heima','19')
  实例化就是真正创建一个该类的对象,baima和heima就是Horse类的实例;每次实例化后获得的实例,都是不同的实例,即使使用同样的参数实例化,得到的也是不一样的对象;python类实例化后,会自动调用__init__方法;这个方法的第一个参数必须留给self,其他参数随意;
__init__方法
  ClassName实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后隐式调用;
  作用:对实例进行初始化;
    class ClassName:
      def __init__(self):
        print('init')
    print(ClassName) #未调用__init__
    print(ClassName()) #临时创建一个对象,调用__init__
    a = ClassName() #创建一个对象,并赋值给a,调用__init__;
  初始化函数可以有多个参数,但是第一个位置必须留给self,self指代当前实例本身;
  init方法被调用的时候,实例就已经存在了;self.name=表示给实例添加了个属性(因为self是一个实例,所以.name是实例的属性;)
  注意:__init__方法不能有返回值,只能是None;其实隐式的在init下面有个return None;

class ClassName:
    def __init__(self):
        print('1','init')
        return None    #init方法不能有返回值,只能是None,隐式的在init方法内有一个return None,正常是可以不写的;
print('2',ClassName)   #只返回了一个类,并没有产生实例,所以不调用init;
print('3',ClassName())  #实例化了一个类,所以调用了init,返回了结果;
a = ClassName()  #同样的道理,实例化了一个类,调用了init,返回了结果
'''
执行结果:
2 <class '__main__.ClassName'>
1 init
3 <__main__.ClassName object at 0x0000020C4A8B6B50>
1 init
'''
class ClassName:
    def __init__(self):
        return 1

print(ClassName())

'''
执行结果:
Traceback (most recent call last):
  File "d:/Doc/test.py", line 13, in <module>      
    print(ClassName())
TypeError: __init__() should return None, not 'int'
进一步证明了在init方法中不能有返回值;
'''

self

class MyClass:
    def __init__(self):
        print('self in init = {}'.format(id(self)))

c = MyClass()  #会调用__init__
print("c = {}".format(id(c)))

'''
打印结果:
self in init = 1653473318728
c = 1653473318728

在真正调用init的时候,其实实例就已经存在了,所以id(self)能取到值;所以前后两个的id值是一样的;进一步说明了self指代的是实例本身;
'''

实例对象instance
  类实例化后一定会获得一个对象,就是实例对象;
  Horse是定义一个类,Horse()创建一个实例,并实例化,baima=Horse()将实例化的值赋给白马,baima就是Horse类的实例对象;
  __init__方法的第一个参数self就是指代某一个实例,这个self就是上述例子中的baima,python会把方法的调用者作为第一参数self的实参传入;
  类实例化后,得到一个实例对象,实例对象会绑定方法,调用方法时采用baima.showname()的方式;
  self.name就是baima对象的name,name是保存在了baima对象上,而不是Horse类上,所以称为实例变量;
实例变量和类变量
  实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法;
  特殊属性    含义
  __name__  对象名
  __class__  对象的类型
  __dict__  对象的属性的字典
  __qualname__  类的限定名
  注意:python中每一种对象都拥有不同的属性;函数、类都是对象,类的实例也是对象;

class Person:
    age = 5
    def __init__(self,name):
        self.name = name
        #self.age = age
    def showage(self):
        print('{} is {}'.format(self.name,self.age))

t = Person('tom')
t.showage()   #age属于类变量,当实例没有age属性的时候就问类去要;
print(Person.age)  ##age属于类变量
Person.age = 30  #为类变量重新赋值
print(t.age)  #原则是一样的,当实例没有的时候问类要;
t.showage() 
'''
执行结果:
tom is 5
5
30
tom is 30
'''
class Person:
    """hello"""
    age = 5
    def __init__(self,name:str): #init方法一旦被调用,则实例已经存在了;
        self.name = name  #给实例添加属性,因为目前self代表的是一个实例;则这是实例的属性;而不是类的属性;
        self.age = 18
    def showage(self):
        pass

print(1,sorted(Person.__dict__.items()))

tom = Person('tom')
print(2,tom.__class__)
print(3,sorted(tom.__dict__.items()))
print(3.1,tom.__dict__)
print(4,sorted(tom.__class__.__dict__.items()))
print(5,Person('jerry').__dict__)
print(6,tom.age)
print(7,tom.__class__.age)
print(8,type(tom).age)
print(9,Person.age)
######
print(Person.__class__)  #类类型的对象
print(Person.__class__.__name__) #类类型的名称
print(Person('jerry').__class__) #问这个实例的类是谁
print(Person('jerry').__class__.__name__) #这个实例的类的名字是什么
#  执行结果
PS D:\Doc> & D:/Python/Python38/python.exe d:/Doc/test.py
1 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', 'hello'), ('__init__', <function Person.__init__ at 0x00000243FDE79F70>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 5), ('showage', <function Person.showage at 0x00000243FDE8A040>)]        
2 <class '__main__.Person'>
3 [('age', 18), ('name', 'tom')]
3.1 {'name': 'tom', 'age': 18}
4 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', 'hello'), ('__init__', <function Person.__init__ at 0x00000243FDE79F70>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 5), ('showage', <function Person.showage at 0x00000243FDE8A040>)]        
5 {'name': 'jerry', 'age': 18}
6 18
7 5
8 5
9 5

  上例中,可以看到类属性保存在类的__dict__中,实例属性保存在实例的__dict__中,如果从实例访问类的属性,就需要借助__class__找到所属的类;

实例属性的查找顺序
  指的是实例使用"."来访问属性,会先找自己的__dict__,如果没有,然后通过属性__class__找到自己的类,再去类的__dict__中找;
  注意,如果实例使用__dict__[变量名]访问变量,将不会按照上面的查找顺序找变量了,这是指明使用字典的key查找,不是属性查找;

posted @ 2020-12-03 13:47  潇湘神剑  阅读(120)  评论(0编辑  收藏  举报