python-类(1)

 

·类(Class)

笔记:

  Python是一种面向对象(Object Oriented)的编程语言,类(Class)是Python的核心概念。在Python中,不管是列表、字符串、函数和类都是对象

  在面向对象编程(OOP)中,任何一个对象都要包含两个部分:属性(是什么)和方法(能做什么)

 

举个例子:小红有某些特征:眼睛大、皮肤白、身材好,这些特征可以比作类中属性;除了特征之外,小红会唱歌、跳舞、弹琴,这些能力可以比作类中的方法:

def 美女:
    眼睛 = 大
    皮肤 = 白
    身材 = 好
    唱歌()
    跳舞()
    弹琴()

将美女类实例化

小红 = 美女()  #小红是一个实例

针对”小红“这个实例,访问属性和使用方法:

小红.眼睛        #访问类中的属性
小红.眼睛 =#修改类中的属性(眼睛由大变小)
小红.唱歌()     #使用类中的方法

 

@类中的基本概念


 创建一个Hello类:

class Hello(object):                     #在python3中,所有类都是类object的子类;定义类也可以写成 class Hello:或者 class Hello():
    def __init__(self,name='world'):     #初始化函数__init__  
        self.name = name                 #类中的属性
    def get_name(self):                  #类中的函数称作方法。
        return 'hello,{}'.format(self.name)

h = Hello('jimmy')   #实例化类(h是实例对象)
print(h.name)        #访问类的属性
print(h.get_name())  #访问类的方法
print('显示h是Hello的实例:',type(h))  
print('显示h是Hello的实例:',h.__class__)  
print('显示h是Hello的实例,类Hello在内存中的地址为(at···):',h)
打印结果:
jimmy
hello,jimmy
显示h是Hello的实例: <class '__main__.Hello'>
显示h是Hello的实例: <class '__main__.Hello'>
显示h是Hello的实例,类Hello在内存中的地址为(at···): <__main__.Hello object at 0x000001A057CE6CC0>

 初始化函数: __init__

初始化函数意味着实例化时要给name提供一个值,通过__init__执行初始化,让实例具有name的属性。由于类Hello中name参数设有默认值,当没有传入参数时,默认为world。

在类外,字符串 'Jimmy' 通过初始化函数__init__()中的 name 参数存入内存中,以Hello类型存在,组成一个对象,这个对象和变量h建立引用关系。这个过程也可以理解成这些数据附加到一个实例上,这样就能通过实例以访问属性的方式访问它。

类中的: Self

在类中, 如果某个地方(比如类中的方法)想要使用实例化传入的数据,那该怎么办?

在类中,将所有传入数据都赋值给一个变量,这个变量是在初始化函数__init__中的第一个参数self。它能接收实例化过程中传入的所有数据,这些数据是根据初始化函数后面的参数导入的。很显然,self就是一个实例,准确说法是应用实例,因为它所对应的就是具体的数据。接下来来验证:

class Hello(object):                    
    def __init__(self,name='world'):  
        self.name = name
     self.address = 'beijing'
print(self) print(type(self)) def get_name(self): return 'hello,{}'.format(self.name) h = Hello()
打印结果:
<__main__.Hello object at 0x0000019FBBBB4E10>
<class '__main__.Hello'>

self实例和h实例一样都有属性。self.name是self的属性,值为name,当然也可以写成self.xxx = name也是可以的。self属性的值不一定要从外部传入,也可以在初始化函数中定义,比如self.address = 'beijing'

在get_name(self)方法中,self是默认的,当类实例化后调用此方法,不需要赋值self能够让return中的语句访问初始函数中传入的值和属性)

类提供默认的行为,而实例可以看成一个工厂。所谓工厂就是可以用一个模板作出很多产品,而类就是模板,实例就是具体的产品。

 

@类属性和实例属性


类是一个对象,有属性;同样,类实例化后也是一个对象,也有它的属性。通过实例化得到的属性称为实例属性,一般情况下可以通过类来访问属性,也可以通过实例来访问属性。

class A:
    x = 1

a = A()
a.x = 5     #更改实例属性
print('实例属性为:',a.x)
print('类属性为:',A.x)
打印结果:
实例属性为: 5
类属性为: 1

实例属性更改了,但类属性没有跟着改变,这是因为类属性不会受实例属性所左右。 

class A:
    x = 1

a = A()
A.x = 10   #更改类属性
print('实例属性为:',a.x)
print('类属性为:',A.x)
打印结果:
实例属性为: 10
类属性为: 10

类属性更改了,实例属性也跟着改变了,说明实例属性受类属性所左右。 

以上所言是指类中的变量引用的是不可变的数据类型(整型、浮点型、字符串、元组),如果引用可变数据类型(字典、列表),数据将发生变化:

class B:
    x = [1,2,3,4]

b = B()
b.x.append(5) #实例属性增加一个值5
print('实例属性:',b.x)
print('类属性:',B.x)
打印结果:
实例属性: [1, 2, 3, 4, 5]
类属性: [1, 2, 3, 4, 5]

当变量中引用的是可变数据类型时,类属性和实例属性都能够直接修改这个对象,从而影响另一方的值。

通过实例和类增加属性:

class B:
    x = [1,2,3,4]

b = B()
B.y = 'hello,world!'       #增加一个类属性
print('实例属性:',b.y) 打印结果: 实例属性: hello,world!

结果表明:通过类增加一个类属性,实例可以访问到它。

如果是用实例增加一个实例属性呢?

class B:
    x = [1,2,3,4]

b = B()
b.y = 'hello,world!'       #增加一个实例属性
print('实例属性:',b.y)
print('类属性:',B.y)
打印结果:
实例属性: hello,world!
Traceback (most recent call last):
  File "test1.py", line 8, in <module>
    print('类属性:',B.y)
AttributeError: type object 'B' has no attribute 'y'

结果表明:增加的实例属性可以通过实例访问,如果通过类访问,结果显示类B中没有属性y。

 

@ 数据流转


在类的应用中,最广泛的是将类实例化,通过实例来执行各种操作。所以对此过程中的数据流转必须弄明白。

class Hello(object):                     
    def __init__(self,name='world'):   
        self.name = name               
    def get_name(self):                 
        return 'hello,{}'.format(self.name)
    def get_color(self,color):
        print('My love color is:',color)
        
h = Hello('jimmy')          
print(h.get_name())         
print(h.get_color('red'))
打印结果:
hello,jimmy
My love color is: red
None                         #由于get_color()方法没有设置返回值,函数默认返回None

 数据流转过程:

创建实例 h = Hello('jimmy'),h 实例和初始化函数中self对应(self接收实例传入的所有数据);'jimmy'是具体的数据,通过初始化函数中的name参数传给self.name(self是个实例,可以设置它的属性),此时name的值为jimmy。

类中除初始化函数以外的方法无论有没有定义参数,都要以self开头,这在类中是不能省略的,这表示所有方法都承接self实例对象。也就是实例的属性被带入到每个方法中,如get_name()中的return 'hello,{}'.format(self.name)语句,self.name调用前面已经确定的实例属性数据为jimmy,所以函数返回hello,jimmy。因此,通过self,可以实现数据在类的内部流转。

如果要把数据从类的内部传到外部,可以通过return语句,由于def get_color():方法没有设置函数返回值,函数默认返回None。

 

@ 类的命名空间和作用域


类命名空间

定义类时,在class语句中的代码都在一个命名空间中执行,即类的命名空间。命名空间是从所定义的命名到对象的映射集合。不同的命名空间可以同时存在但彼此相互独立。

命名空间因对象不同,可以分为以下几种:

内置命名空间:

内置函数的命名空间都属于内置命名空间,因此,可以在程序中直接运行它们。比如print()函数id()函数等拿来就可以直接使用。

全局命名空间:

每个模块都有自己的全局命名空间,不同模块的全局命名空间彼此独立;不同模块相同名称的命名空间,因为模块不同而不会相互干扰。

本地命名空间:

模块中有类和函数 ,每个类或者函数所定义的命名空间就是本地命名空间。如果函数返回结果或者异常,本地命名空间也将结束。

各个命名空间的关系(图片来源于网络):

 

访问命名空间的时候,就按照从里到外的顺序:

def Duo(x,y):
    name = 'jimmy'
    return locals()
    
print(Duo('he','llo'))
打印结果:
{'x': 'he', 'y': 'llo', 'name': 'jimmy'}

通过locals()访问本地命名空间的方法,命名空间中的数据存储结构和字典一样;也可以通过globals()访问全局命名空间。

作用域:是指在python程序中可以直接访问到的命名空间。直接访问意味着访问命名空间中的命名时无需附加任何修饰语。程序按照命名空间从里到外的顺序,搜索相应命名空间能够访问到的作用域。

def out_t():
    b = 10
    def in_t():
        c= 20
a = 30

假设我在def in_t():函数中,c对于我来说就是本地作用域,而a和b不是;如果我在def in_t():函数中新增加一个对象(b = 20),这和def out_t():中的b不会冲突,因为他们的作用域不同。

接下来我们证实:

def out_t():
    a = 10
    def in_t():
        a = 20
        print('in_t,a=',a)
    in_t()
    print('out_t,a=',a)

a = 30

print(out_t())
print('a=',a)
打印结果:
in_t,a= 20
out_t,a= 10
None
a= 30

 

end~

****** 几米花的Python ****** 博客主页:https://www.cnblogs.com/jimmy-share/  欢迎转载 ~
posted @ 2018-12-16 21:29  jimmy0k  阅读(440)  评论(0编辑  收藏  举报