【问题标题】:Appended object to a set is `NoneType` python 2.7附加到集合的对象是`NoneType` python 2.7
【发布时间】:2016-07-22 13:26:22
【问题描述】:

我有大量标签,我通过以下方式制作独一无二的标签:

unique_train_labels = set(train_property_labels)

打印为set([u'A', u'B', u'C'])。我想使用名为“no_region”的新标签创建一组新的唯一标签,并且正在使用:

unique_train_labels_threshold = unique_train_labels.add('no_region')

但是,这打印出来是None

我的最终目标是使用这些独特的标签,然后通过以下方式生成一个随机的分类标签数组:

    rng = np.random.RandomState(101)

    categorical_random = rng.choice(list(unique_train_labels), len(finalTestSentences))
    categorical_random_threshold = rng.choice(list(unique_train_labels_threshold), len(finalTestSentences))

docs 中说set.add() 应该生成一个新集合,但似乎并非如此(因此我以后不能调用list(unique_train_labels_threshold)

【问题讨论】:

  • 文档在哪里说 add 方法生成一个新集合?我只发现:s.add(x) add element x to set s
  • 你应该这样做 int 2 次。首先将unique_train_labels 存储在unique_train_labels_threshold 中,然后在unique_train_labels_threshold 上调用add()a_set.add(stuff) 总是return none
  • @cdarke 是的,这就是我的意思,它说它向集合中添加了一个元素,这对我来说似乎意味着集合应该仍然存在..
  • @pwnsauce 你能澄清一下我能做些什么以便我可以使用新的集合a_set.add(stuff)吗?

标签: python python-2.7 numpy random set


【解决方案1】:

正如摩西的回答中提到的,set.add 方法会改变原始集合,它不会创建新集合。在 Python 中,执行就地突变的方法通常返回None;所有内置可变类型的方法都这样做,并且该约定通常由 3rd-party 库遵守。

使用.copy 方法的替代方法是使用.union 方法,该方法返回一个新集合,该集合是原始集合和作为参数提供的集合的并集。对于集合,| or 运算符调用.union 方法。

a = {1, 2, 3}
b = a.union({5})
c = a | {4}
print(a, b, c)

输出

{1, 2, 3} {1, 2, 3, 5} {1, 2, 3, 4}

.union 方法(与其他可以通过运算符语法调用的 set 方法一样)比运算符语法有一点优势:您可以将其传递 any 可迭代的参数;运算符版本要求您将参数显式转换为集合(或 freezeset)。

a = {1, 2, 3}
b = a.union([5, 6])
c = a | set([7, 8])
print(a, b, c)

输出

{1, 2, 3} {1, 2, 3, 5, 6} {1, 2, 3, 7, 8}

在这里使用显式.union 方法效率稍高一些,因为它绕过了将arg 转换为集合:在内部,该方法只是迭代arg 的内容,将它们添加到新集合中,所以它不会关心 arg 是集合、列表、元组、字符串还是字典。

来自Python官方set docs

注意,union()、intersection() 的非运算符版本, difference() 和 symmetric_difference()、issubset() 和 issuperset() 方法将接受任何可迭代的作为参数。相比之下,他们的 基于运算符的对应项需要设置它们的参数。这个 排除像 set('abc') & 'cbs' 这样容易出错的结构,有利于 更具可读性的 set('abc').intersection('cbs')。

【讨论】:

    【解决方案2】:

    集合add 方法对集合就地 进行变异并返回None

    你应该这样做:

    unique_train_labels_threshold = unique_train_labels.copy()
    unique_train_labels_threshold.add('no_region')
    

    使用copy 可确保新集上的突变不会传播到旧集。

    【讨论】:

    • 抱歉,这不起作用 - 它仍然打印到 None
    • 您以某种方式将原始设置修改为None。重新创建第一组
    • @pwnsauce 如果您不copy,您对new 集所做的更改将出现在old 中,这不是在这种情况下是可取的。它们都将引用相同的对象而没有副本(因此没有新的,没有旧的,但相同的对象)
    • @pwnsauce 对于 mutable 对象,赋值不会创建新副本,而是对原始对象的引用
    • @MosesKoledoye:不可变对象也是如此,但通常没关系,因为它们是不可变的。 :) 例如,a=(1,2,3); b=a; print(id(a),id(b))
    【解决方案3】:

    我在文档中找不到任何地方说add 生成了一个新集合。
    您需要复制原件,然后添加到新副本中。

    import copy
    
    unique_train_labels_threshold = copy.deepcopy(unique_train_labels)
    unique_train_labels_threshold.add('no_region')
    

    【讨论】:

    • 抱歉,这不起作用 - 它仍会打印到 None
    • 在集合元素上使用deepcopy 太过分了。 set.copy 方法总是足够的,因为集合元素必须是完全不可变的。您甚至不能将列表元组设为集合元素。
    • @PM2Ring:我使用它的原因是因为文档特别说明copy 方法做了浅拷贝。
    • 对于完全不可变的对象来说,浅拷贝是完全足够的。 IOW,任何需要 deepcopy 才能安全复制的对象不能 是集合元素。
    • 当然,这与 OP 的情况几乎无关,因为他们只需要一组字符串,这些字符串显然是不可变的。
    猜你喜欢
    • 2017-01-08
    • 2013-09-19
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 2014-05-02
    • 2011-03-24
    • 1970-01-01
    相关资源
    最近更新 更多