python中为什么类的实例方法可以直接访问全局变量?

# Python queue队列,实现并发,在网站多线程推荐最后也一个例子,比这货简单,但是不够规范

# encoding: utf-8
__author__ = 'yeayee.com'  # 由本站增加注释,可随意Fork、Copy

from queue import Queue  # Queue在3.x中改成了queue
import random
import threading
import time


class Producer(threading.Thread):
    """
    Producer thread 制作线程
    """
    def __init__(self, t_name, queue):  # 传入线程名、实例化队列
        threading.Thread.__init__(self, name=t_name)  # t_name即是threadName
        self.data = queue

    """
    run方法 和start方法:
    它们都是从Thread继承而来的,run()方法将在线程开启后执行,
    可以把相关的逻辑写到run方法中(通常把run方法称为活动[Activity]);
    start()方法用于启动线程。
    """

    def run(self):
        for i in range(5):  # 生成0-4五条队列
            print("%s: %s is producing %d to the queue!" % (time.ctime(), self.getName(), i))  # 当前时间t生成编号d并加入队列
            self.data.put(i)  # 写入队列编号
            time.sleep(random.randrange(10) / 5)  # 随机休息一会
        print("%s: %s producing finished!" % (time.ctime(), self.getName))  # 编号d队列完成制作


class Consumer(threading.Thread):
    """
    Consumer thread 消费线程,感觉来源于COOKBOOK
    """
    def __init__(self, t_name, queue):
        threading.Thread.__init__(self, name=t_name)
        self.data = queue

    def run(self):
        for i in range(5):
            val = self.data.get()
            print("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(), self.getName(), val))  # 编号d队列已经被消费
            time.sleep(random.randrange(10))
        print("%s: %s consuming finished!" % (time.ctime(), self.getName()))  # 编号d队列完成消费


def main():
    """
    Main thread 主线程
    """
    queue = Queue()  # 队列实例化
    producer = Producer('Pro.', queue)  # 调用对象,并传如参数线程名、实例化队列
    consumer = Consumer('Con.', queue)  # 同上,在制造的同时进行消费
    producer.start()  # 开始制造
    consumer.start()  # 开始消费
    """
    join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
  join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。
    """
    producer.join()
    consumer.join()
    print('All threads terminate!')


if __name__ == '__main__':
    main()


"""运行结果:

Thu Feb  4 11:05:48 2016: Pro. is producing 0 to the queue!
Thu Feb  4 11:05:48 2016: Pro. is producing 1 to the queue!
Thu Feb  4 11:05:48 2016: Con. is consuming. 0 in the queue is consumed!
Thu Feb  4 11:05:49 2016: Pro. is producing 2 to the queue!
Thu Feb  4 11:05:50 2016: Pro. is producing 3 to the queue!
Thu Feb  4 11:05:51 2016: Pro. is producing 4 to the queue!
Thu Feb  4 11:05:52 2016: Con. is consuming. 1 in the queue is consumed!
Thu Feb  4 11:05:53 2016: <bound method Producer.getName of <Producer(Pro., started 6864)>> producing finished!
Thu Feb  4 11:06:00 2016: Con. is consuming. 2 in the queue is consumed!
Thu Feb  4 11:06:06 2016: Con. is consuming. 3 in the queue is consumed!
Thu Feb  4 11:06:06 2016: Con. is consuming. 4 in the queue is consumed!
Thu Feb  4 11:06:12 2016: Con. consuming finished!
All threads terminate!

"""

我刚刚试了一下,上面的代码中即使在def __init__里面不传入那个queue,而是直接在run方法里面调用对应的变量,确实仍然可以直接访问,那么为什么还要有global这个关键字?

这样设计是否有不合理之处?

self.xxx和xxx的区别是否就是为了区分类的内部变量和全局变量?

阅读 12.1k
4 个回答

Producer和Consumer在一个文件里面确实体现不出来封装的好处。

试下一下,如果程序足够复杂,以至于Producer和Consumer不在一个文件里面,那么是不是要考虑如何使用这个变量呢。

OOP思想:封装,继承和多态,模块化,解耦化,只有从工程化角度来考虑才会觉得真的解决了不少问题。

不太明白题主的意思.题主的意思是在线程的__init__方法中不将queue赋给self.data吗?
另外, global存在的意义是,当在函数内引用了在全局定义的变量时,如果没有global,可以读取,而写操作时,只对函数内部的该变量进行操作,而全局变量不变.使用global后,则会改变全局.
另外,全局变量和内部变量同名是很不好的习惯.

你好,我也是在类中使用队列,可以我把创建的队列mybuffer设置成了全局变量就又有问题,实际在windows的cmd中的的执行情况是class Producer中的的queue.put()一直在执行,但是class Consumer中的get()确一直没有得到队列中的元素,感觉这个mybuffer到两个类中变成了局部变量。

clipboard.png

如果我把mybuffer当做参数分别传到两个类中是可以正常的put()和get()的

clipboard.png

不知道全局变量的队列在类里面却不能用了。。。。。。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from multiprocessing import Process, Semaphore, Lock, Queue
import time


mybuffer = Queue(10)
#empty = Semaphore(2)
#full = Semaphore(1)

class Consumer(Process):
    def __init__(self,lock):
        Process.__init__(self)
        self.lock = lock
    def run(self):
        global mybuffer
        while True:
            #full.acquire()
            mybuffer.get()
            self.lock.acquire()
            print('Consumer pop an element')
            self.lock.release()
            time.sleep(1)
            #empty.release()


class Producer(Process):
    def __init__(self,lock):
        Process.__init__(self)
        self.lock = lock
    def run(self):
        global mybuffer
        while True:
            #empty.acquire()
            mybuffer.put('1')
            self.lock.acquire()
            print('Producer append an element')
            self.lock.release()
            time.sleep(1)
            #full.release()


if __name__ == '__main__':
    #mybuffer = Queue(10)
    lock = Lock()
    p = Producer(lock)
    c = Consumer(lock)
    #p.daemon = c.daemon = True
    c.start()
    p.start()
    #c.start()
    p.join()
    c.join()
    print 'Ended!'

结果:

self.xxx是实例变量,是每个实例独自有的。xxx定义在class里方法外就是类变量。定义在模块级别的就是最外面不在方法里也不在class里的就是全局变量。global的作用楼上已经说了。题主可以了解下python变量的命名空间和作用域即LEGB. PS: 还请看下评论,以防回答引起误解

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题