面向对象的思维去设计程序

什么是面向对象编程

面向对象编程是一种程序的范式,它把程序看成是对不同对象的相互调用,对现实世界建立的一种模型。在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。

什么是类

class ClassMate:
       block

类的名字常常以大写开头  驼峰命名法

  

程序中类的用法
. 专门用来访问属性,本质操作的就是__dict__
OldboyStudent.school #等于经典类的操作OldboyStudent.__dict__['school']
OldboyStudent.school='Oldboy' #等于经典类的操作OldboyStudent.__dict__['school']='Oldboy'
OldboyStudent.x=1 #等于经典类的操作OldboyStudent.__dict__['x']=1
del OldboyStudent.x #等于经典类的操作OldboyStudent.__dict__.pop('x')

什么是类对象

注意类名后面有个冒号,在block块里面就可以定义属性和方法了。当一个类定义完之后,就产生了一个类对象。类对象支持两种操作:引用和实例化。引用操作是通过类对象去调用类中的属性或者方法,而实例化是产生出一个类对象的实例,称作实例对象。比如定义了一个goods类

class goods:
    name = 'apple'       #定义了一个属性
    #定义了一个方法
    def printName(self):
        print(self.name)
abc=goods()
abc.printName()
'''apple
'''

goods类定义完成之后就产生了一个全局的类对象,可以通过类对象来访问类中的属性和方法了。

在上面代码中注释的很清楚了,name是一个属性,printName( )是一个方法,与某个对象进行绑定的函数称作为方法。一般在类里面定义的函数与类对象或者实例对象绑定了,所以称作为方法;而在类外定义的函数一般没有同对象进行绑定,就称为函数。

python为类内置的特殊属性

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

更好的理解类对象

class goods:
    name = 'apple'       #定义了一个属性
    def __init__(self,name):
         self.name=name
#类对象产生,其实goods默认继承了object类,类对象的产生与object里面的内置方法有关系

print(goods.__dict__)

sdsd=goods('scscs')

print(goods.__dict__)

'''
{'__module__': '__main__', 'name': 'apple', '__init__': <function goods.__init__ at 0x00000237D68798C8>, '__dict__': <attribute '__dict__' of 'goods' objects>, '__weakref__': <attribute '__weakref__' of 'goods' objects>, '__doc__': None}
{'__module__': '__main__', 'name': 'apple', '__init__': <function goods.__init__ at 0x00000237D68798C8>, '__dict__': <attribute '__dict__' of 'goods' objects>, '__weakref__': <attribute '__weakref__' of 'goods' objects>, '__doc__': None}
可以看出来类里面的__init__只是初始化类的实例化结果,类的名称空间不发生变化
如果变量name没有被初始化,对象sdsd也可以使用父类的name变量
'''

print(sdsd.__dict__)
'''{'name': 'scscs'}
'''

属性

class people:  
    name = 'jack'  
    age = 12  
 
p = people()  
print(p.name,p.age)

定义了一个people类,里面定义了name和age属性,默认值分别为'jack'和12。在定义了类之后,就可以用来产生实例化对象了,这句p = people( )实例化了一个对象p,然后就可以通过p来读取属性了。这里的name和age都是公有的,可以直接在类外通过对象名访问,如果想定义成私有的,则需在前面加2个下划线 ' __'

class people:  
    __name = 'jack'  
    __age = 12  
  
p = people()  
print(p.__name,p.__age)

程序运行会报错

Traceback (most recent call last):  
  File "C:/PycharmProjects/FirstProject/oop.py", line 6, in <module>  
    print p.__name,p.__age  
AttributeError: people instance has no attribute '__name

提示找不到该属性,因为私有属性是不能够在类外通过对象名来进行访问的。在Python中没有像C++中public和private这些关键字来区别公有属性和私有属性,它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)

类即类型

python中一切皆为对象,且python3中类与类型是一个概念,类型就是类

#类型dict就是类dict
>>> list
<class 'list'>

#实例化的到3个对象l1,l2,l3
>>> l1=list()
>>> l2=list()
>>> l3=list()

#三个对象都有绑定方法append,是相同的功能,但内存地址不同
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>

#操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3
>>> l1.append(3)
>>> l1
[3]
>>> l2
[]
>>> l3
[]
#调用类list.append(l3,111)等同于l3.append(111)
>>> list.append(l3,111) #l3.append(111)
>>> l3
[111] 

补充: 我们都知道Python一切皆对象,那么Python究竟是怎么管理对象的呢?

1、无处不在的__dict__
首先看一下类的__dict__属性和类对象的__dict__属性
由此可见, 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
对象的__dict__中存储了一些self.xxx的一些东西

2、Python里什么没有__dict__属性
虽然说一切皆对象,但对象也有不同,就好比不是每个人的女朋友都是一个人一样,一些内置的数据类型是没有__dict__属性的,如下
num = 3
ll = []
dd = {}
print num.__dict__
print ll.__dict__
print dd.__dict__

3、发生继承时候的__dict__属性
 子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中
1)每个类的类变量、函数名都放在自己的__dict__中
2)子类对象可以用父类的__dict__里面的值

总结:
1) 内置的数据类型没有__dict__属性
2) 每个类有自己的__dict__属性,就算存着继承关系,父类的__dict__ 并不会影响子类的__dict__
3) 对象也有自己的__dict__属性, 存储self.xxx 信息
无处不在的__dict__

方法

在类中可以根据需要定义一些方法,定义方法采用def关键字,在类中定义的方法至少会有一个参数,一般以名为'self'的变量作为该参数(用其他名称也可以),而且需要作为第一个参数。下面看个例子:

class people:  
    __name = 'jack'  
    __age = 12  
  
    def getName(self):  
        return self.__name  
    def getAge(self):  
        return self.__age  
  
p = people()  
print p.getName(),p.getAge()  
View Code

类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法

总结:类的数据属性是大家共有的,而且大家的内部地址是一样的,用的就是一个
         类的函数属性是绑定到大家身上的,内部地址不一样,绑定方法指的是绑定到对象身上。
         绑定方法:绑定到谁的身上,就是给谁用的,谁来调用就会自动把自己当做第一个参数传入。

定义在类内部的变量,是所有对象共有的,id全一样,
如果类想调用绑定方法,就必须遵循函数的参数规则,有几个参数,就必须传递几个参数。 
定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.fun()会把obj本身当做一个参数来传递。



在类内部定义的函数虽然可以由类来调用,但是并不是为了给类用的,在类内部定义的函数的目的就是为了绑定到对象身上的。

在类的内部来说,__init__是类的函数属性,但是对于对象来说,就是绑定方法。

命名空间的问题:先从对象的命名空间找,随后在从类的命名空间找,随后在从父类的命名
空间找。

在定义类的时候,可以想什么先写什么。
总结绑定方法

强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)

s1.learn()     #等同于OldboyStudent.learn(s1)
s2.learn()     #等同于OldboyStudent.learn(s2)
s3.learn()     #等同于OldboyStudent.learn(s3)
注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。

如果对self不好理解的话,可以把它当做C++中类里面的this指针一样理解,就是对象自身的意思,在用某个对象调用该方法时,就将该对象作为第一个参数传递给self。

#类的数据属性是所有对象共享的,id都一样
print(id(OldboyStudent.school))

print(id(s1.school))
print(id(s2.school))
print(id(s3.school))

'''
4377347328
4377347328
4377347328
4377347328
'''

#类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样
#ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准
print(OldboyStudent.learn)
print(s1.learn)
print(s2.learn)
print(s3.learn)
'''
<function OldboyStudent.learn at 0x1021329d8>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>>
类的数据属性与函数属性分析

注意点:

构造方法__init__(self,....):在生成对象时调用,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。构造方法支持重载,如果用户自己没有重新定义构造方法,系统就自动执行默认的构造方法。

 __init__():__init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望得到的初始化

# Filename: class_init.py  
class Person:  
    def __init__(self, name):  
        self.name = name  
    def sayHi(self):  
        print 'Hello, my name is', self.name  
  
p = Person('Swaroop')  
p.sayHi()  
  
输出:  
Hello, my name is Swaroop 


#__init__的必须注意的点
1、该方法内可以有任意的python代码
2、一定不能有返回值

  

原文地址:https://www.cnblogs.com/596014054-yangdongsheng/p/9830265.html