【问题标题】:How do you create an incremental ID in a Python Class如何在 Python 类中创建增量 ID
【发布时间】:2010-11-05 22:21:02
【问题描述】:

我想为我创建的每个对象创建一个唯一的 ID - 这是类:

class resource_cl :
    def __init__(self, Name, Position, Type, Active):
        self.Name = Name
        self.Position = Position
        self.Type = Type
        self.Active = Active

我想要一个 self.ID,每次创建对类的新引用时都会自动递增,例如:

resources = []
resources.append(resource_cl('Sam Sneed', 'Programmer', 'full time', True))

我知道我可以引用 resource_cl,但我不确定如何从那里继续...

【问题讨论】:

  • 接受的答案没有回答问题

标签: python class


【解决方案1】:

您好,这可能是漫长的方式,但对我来说非常流畅。希望能帮助到你。 我已经使用名为 id.txt.

的外部文本文件完成了它

只需创建一个如上所述命名的空文件。 然后运行这个 sn-p。这肯定会奏效。

def id_generator():
with open("id.txt", "r") as f:
    f.seek(0)
    fc = f.read(1)
    if not fc:
        with open("id.txt", "w") as f1:
            f1.write("1")
        id = 1
    else:
        f.seek(0)
        fc = f.read(1)
        nv = int(fc) + 1
        with open("id.txt", "w") as f2:
            f2.write(str(nv))
        id = nv

return id

要从此片段中获取价值,请执行此操作。

id = id_generator()

如果任何读者觉得它有用,请发表评论,让我知道我的工作是否得到了回报。

希望对您有所帮助。 谢谢......

【讨论】:

    【解决方案2】:

    您可以将计数作为类参数附加到类,然后在初始化时,您可以将此值复制到实例参数。

    这使得count 成为类参数,id 成为实例参数。这是可行的,因为整数在 python 中是不可变的,因此复制的是当前值而不是属性本身。

    class Counter:
        count = 0
    
        @classmethod
        def incr(self):
            self.count += 1
            return self.count
    
        def __init__(self):
            self.id = self.incr()
    
    assert [Counter().id for _ in range(3)] == [1, 2, 3]
    

    【讨论】:

      【解决方案3】:

      在 python 3 中尝试投票最高的答案会遇到错误,因为 .next() 已被删除。

      相反,您可以执行以下操作:

      import itertools
      
      class BarFoo:
      
          id_iter = itertools.count()
      
          def __init__(self):
              # Either:
              self.id = next(BarFoo.id_iter)
      
              # Or
              self.id = next(self.id_iter)
              ...
      

      【讨论】:

      • 这应该是公认的答案。它就像一个魅力!
      • 我想收藏这个答案。但 SA 只允许我为问题添加书签!
      • 我可以点击关注,然后我就可以轻松访问了!
      【解决方案4】:

      你知道python中的id function,你能用它来代替你的反击吗?

      class C(): pass
      
      x = C()
      y = C()
      print(id(x), id(y))    #(4400352, 16982704)
      

      【讨论】:

      • 我在课堂上使用了 id(self) - 似乎是满足我需求的正确解决方案 - 谢谢
      • 请记住,id() 返回的值不能保证在程序的一次执行中是唯一的(它们可以在收集对象时被重用)。它们也不保证遵循任何特定模式(您最初确实要求自动递增)。
      • R.佩特:绝对正确,重要的是要牢记;我只是想确保他知道 id 函数的存在并在选择手动执行某些操作之前对其进行正确评估。
      • 如果要腌制对象,无论是存档还是网络 io,使用内置 id() 是不明智的。另一端的计算机可能已经有一个具有该 id() 的对象。
      • @DevPlayer 最后一句对应于你正在挑战的 Roger Pate 的那句话。
      【解决方案5】:

      我喜欢使用生成器生成 id。允许生成器维护已使用的 id 列表。

      # devplayer@gmail.com
      # 2012-07(jul)-19
      
      
      class MakeUniqueStr(object):
          '''
          unqstr = MakeUniqueStr(default_name='widget', sep='_')
          print(repr(unqstr('window')))
          print(repr(unqstr('window')))
          print(repr(unqstr('window')))
          print(repr(unqstr('hello')))
          print(repr(unqstr('hello')))
          print(repr(unqstr('window')))
          print(repr(unqstr('hello')))
      
          'window'
          'window_00000'
          'window_00001'
          'hello'
          'hello_00000'
          'window_00002'
          'hello_00001'
          '''
      
          def __init__(self, default_name='default', sep='_'):
              self.default_name = default_name
              self.last_base_name = default_name
              self.sep = sep
      
              self.used_names = []
      
              self.generator = self.Generator()
              self.generator.next() # initialize
      
          def __call__(self, name=None):
              if name <> None: self.last_base_name = name
              return self.generator.send(self.last_base_name)
      
          def _MakeName(self, name, index=1):
              '''_MakeName is called by the Generator. 
      
              Generator will always have a name and an index to pass to _MakeName. 
              Over ride this method to customize it.'''
      
              return name + self.sep + '%0.5d' % index
      
          def Generator(self):
              try_name = yield 'ready' # initialize
              index = 0
              while 1:
      
                  if try_name not in self.used_names:
                      self.used_names.append( try_name )
                      sent_name = yield try_name
                      try_name = sent_name
                      continue
      
                  try_name = self._MakeName( sent_name, index )
                  while try_name in self.used_names:
                      index += 1
                      try_name = self._MakeName( sent_name, index )
      
                  index = 0
      

      虽然这对于内存中的大型数据集来说不是一种高效的内存方式。如果您想使用类似的东西,请修改它以让操作系统处理缓存到文件...例如通过命名管道。

      【讨论】:

        【解决方案6】:

        ID 有时会受益于使用您想要引用的对象的某些字段。这是一种老式的数据库技术。

        例如,如果您有一个应用记录来电客户的电话,那么可能会使用由时间生成的 id = 其他东西

        ident = '%s:%.4s:%.9s' % ( time.time(), time.clock(), agent.name )
        # don't forget to time.clock() once to initialize it
        

        请注意 time.time() 和 time.clock() 是单独的计算机返回值,除非在服务器上生成。如果在服务器上,请确保您的服务器时钟设置正确;一如既往。

        【讨论】:

          【解决方案7】:

          关于 id() 的另一个注释并重新考虑其他人的答案。 id() 可能会返回一个唯一的数字,当且仅当它记住曾经返回的每个 id,即使一个对象被删除;它(id())不这样做。所以所以...

          为了支持其他人所说的 id() 不返回唯一数字;确实,当且仅当您将这些 id() 值存储为对对象的引用并且您正在删除您正在为其获取 id() 的对象的实例时,它才能保证唯一的值。但 !使用 id() 作为参考意味着您基本上拥有一个对象,该对象具有与另一个对象以某种方式链接的键。

          这不会因 id() 的非唯一性而失效。仅当您不检查添加新对象是否已将预先存在的 id() 存储为对该对象其他实例的引用时,它才会失效。

          storeit = {}
          
          object1 = object()
          print id(object1)
          4357891223
          
          storeit[ id(object1) ] = object1
          
          object2 = object()
          print id(object2)
          9834923411
          
          storeit[ id(object2) ] = object2
          
          storeit[ id(object1) ] = object()
          del object1
          
          object3 = object()
          print id(object3)
          # after some 2 gigawatt tries magically i got
          4357891223
          # the same id as object1 had
          

          BUT storeit[ 4357891223 ] 返回一些其他对象实例,而不是 object3;因此 仍然有效,但唯一性失败。

          【讨论】:

            【解决方案8】:

            简洁优雅:

            import itertools
            
            class resource_cl():
                newid = itertools.count().next
                def __init__(self):
                    self.id = resource_cl.newid()
                    ...
            

            【讨论】:

            • +1:这是所有当前答案中唯一可靠且线程安全的方法。 id 可能返回非唯一值,并且简单地增加 __init__ 内的类变量可能会导致竞争条件。我也喜欢将引用存储到count().next 而不是直接存储count() 的结果的想法。
            • 它使用 id() 发生在同一个对象上,例如a="123" b="123" id(a) == id(b)
            • @clsung Python 字符串是“interned”并且它们是不可变的。 “123”是您的 Python 会话中的同一个对象。 “a”和“b”是命名引用,而不是“123”的“对象”或“实例”。在这种情况下,它们指向一个实习字符串。 Google python 实习生了解更多信息。
            • Python3 已经删除了.next(),所以你可以试试这个:stackoverflow.com/a/54318273/3407256
            • 正如@foxyblue 所说,python3 删除了 .next() 并将其替换为 next 内置函数。然而,next 内置函数只引用了count 返回的迭代器的__next__ 方法,因此您可以将.next 替换为.__next__
            【解决方案9】:

            使用来自itertools 的计数非常适合:

            >>> import itertools
            >>> counter = itertools.count()
            >>> a = next(counter)
            >>> print a
            0
            >>> print next(counter)
            1
            >>> print next(counter)
            2
            >>> class A(object):
            ...   id_generator = itertools.count(100) # first generated is 100
            ...   def __init__(self):
            ...     self.id = next(self.id_generator)
            >>> objs = [A(), A()]
            >>> print objs[0].id, objs[1].id
            100 101
            >>> print next(counter) # each instance is independent
            3
            

            如果您以后需要更改值的生成方式,则相同的接口可以工作,您只需更改id_generator 的定义。

            【讨论】:

              【解决方案10】:

              首先,为类使用大写名称。属性的小写名称。

              class Resource( object ):
                  class_counter= 0
                  def __init__(self, name, position, type, active):
                      self.name = name
                      self.position = position
                      self.type = type
                      self.active = active
                      self.id= Resource.class_counter
                      Resource.class_counter += 1
              

              【讨论】:

              • init 中,class_counter 引用是类的一个属性。它应该是这样的:Resource.class_counter += 1
              • S.Lott,我试过了。在您的第一个版本中,每个对象的 id 为 0,class_counter 为 1。
              • self 将在访问值的情况下工作。因此: self.id= self.class_counter 将按照需要执行,因为属性解析将回退到类属性。这不是设置属性的情况,因为值集将在实例的范围内,而不是基础类。
              • += 运算符可能会产生非常令人惊讶的结果,因为它对不同类型的工作方式不同。而且不仅仅是在 [im] 可变性线上,例如一个带有 add 但不是(可能被遗忘的)iadd 的可变类。
              • 如果你需要支持类继承,你可能想使用self.__class__.class_counter += 1而不是Resource.class_counter += 1
              猜你喜欢
              • 2023-03-15
              • 2013-07-27
              • 2018-12-13
              • 1970-01-01
              • 2015-09-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-04-23
              相关资源
              最近更新 更多