Python线程范围

时间:2016-08-02 09:39:41

标签: python scope

这两个代码似乎都有类似的表现。在这种情况下,范围如何工作?他们中的任何一个比另一个好吗?有没有更好的方法来实现相同的行为?

代码1:

class ex:
  b = 6
  def foo(self, a):
    def fooHandler(a):
      while True:
        print a
        time.sleep(1)
    threading.Thread(target=fooHandler, args=(a,)).start()
x = ex()
x.foo(10)
x.foo(100)
x.foo(1000)

代码2:

class ex:
  b = 6
  def foo(self, a):
    def fooHandler():
      while True:
        print a
        time.sleep(1)
    threading.Thread(target=fooHandler).start()
x = ex()
x.foo(10)
x.foo(100)
x.foo(1000)

2 个答案:

答案 0 :(得分:1)

嗯,生成代码的差异(至少在使用CPython 2.7.12时):

def runThread(a):
    def threadFunc():
        while True:
            print a
            time.sleep(1)

    t = threading.Thread(target=threadFunc)
    t.start()

将在LOAD_GLOBAL内为a发出threadFunc()操作码(输出来自inspect.dis.dis()):

8           9 LOAD_GLOBAL              1 (a)

,而

def runThread(a):
    def threadFunc(a):
        while True:
            time.sleep(1)

    t = threading.Thread(target=threadFunc, args=(a, ))
    t.start()

将发出LOAD_FAST操作码:

8           9 LOAD_FAST                0 (a)

LOAD_FAST发生,因为编译器知道a是参数,因此查找只需要发生wrt。到当前的命名空间。 LOAD_FAST(因此名称)可能比LOAD_GLOBAL更快,但如果您需要考虑性能方面的差异,您可能不应该首先使用Python。

是的,一切都向我尖叫“实施细节”。

从外部作用域导入a可以增加灵活性,因为即使在线程已经运行之后,您仍然可以修改a。将a作为参数传递给线程函数时,这种可能性或多或少都消失了。在任何情况下,除非a是线程终止标志,否则我会认为前者是反模式。

答案 1 :(得分:0)

这与线程无关,它只是使用嵌套作用域中的值与显式作为参数传递并在本地作用域中使用它的问题。

在这种情况下,您使用哪种方法并不特别重要;你在任何一种情况下都使用相同的值。在嵌套范围中查找它是更昂贵的,但只是非常简单(它基本上等同于单个ConvertXmlToClass<T>查找,其中本地范围查找更接近阵列访问性能)。

如果您需要在函数期间更改public class AdminManager : IAdminService { public IEnumerable<SecurityGroup> SecurityGroups() { IEnumerable<SecurityGroup> list = null; XmlDocument xmlDoc = new XmlDocument(); using (var c = new FMContext()) { var xmlData = c.Database.SqlQuery<string>("AllSecurtyUsersProc").FirstOrDefault(); if (xmlData != null) { xmlDoc.LoadXml(xmlData); list = ConvertXmlToClass<SecurityGroup>(xmlDoc, "/SecurityGroups/SecurityGroup"); } } return list; } public static IEnumerable<T> ConvertXmlToClass<T>(XmlDocument doc, string nodeString) where T : class, new() { var xmlNodes = doc.SelectNodes(nodeString); List<T> list = new List<T>(); foreach (XmlNode node in xmlNodes) { var item = GetNewItem<T>(node); list.Add(item); } return list; } public static T GetNewItem<T>(XmlNode node) where T : class, new() { var type = typeof(T); var item = new T(); var properties = type.GetProperties(); foreach (var property in properties) { var propertyType = property.PropertyType; var propertyName = property.Name; object value = null; if (IsEnumerable(property)) { value = GetNodeCollectionValue(property, node); } else { value = GetNodeValue(node, propertyName); } if (value != null) { property.SetValue(item, Convert.ChangeType(value, propertyType), null); } } return item; } private static object GetNodeCollectionValue(PropertyInfo property, XmlNode node) { var doc = new XmlDocument(); var itemType = property.PropertyType.GenericTypeArguments[0]; var xml = node.InnerXml; if (xml.Contains(property.Name)) { var start = xml.IndexOf($"<{property.Name}>"); var length = xml.IndexOf($"</{property.Name}>") - start + ($"</{property.Name}>").Length; xml = xml.Substring(start, length); doc.LoadXml(xml); if (itemType != null) { var type = typeof(AdminManager); var methodInfo = type.GetMethod("ConvertXmlToClass"); if (methodInfo != null) { var method = methodInfo.MakeGenericMethod(itemType); if (method != null) { object[] args = { doc, $"/{property.Name}/{itemType.Name}" }; object result = method.Invoke(null, args); var r = result as IEnumerable<object>; return r; } } } } return null; } private static bool IsEnumerable(PropertyInfo property) { var type = property.PropertyType; return typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType; } private static object GetNodeValue(XmlNode node, string nodeName) { if (node[nodeName] != null) { var i = node[nodeName].InnerText; return i; } return null; } } 的绑定,则无法使用隐式嵌套范围访问权限(您必须使用其他名称),因为您可以使用#{1}}。 t从Python 2中的嵌套范围变量读取和写入(缺少dict关键字)。使用不同的名称(最初设置为a)类似于在任何情况下接受它作为参数,所以再次,没有重大区别。