简体   繁体   English

如何在 Python Class 中创建增量 ID

[英]How do you create an incremental ID in a Python Class

I would like to create a unique ID for each object I created - here's the class:我想为我创建的每个 object 创建一个唯一 ID - 这是 class:

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

I would like to have a self.ID that auto increments everytime I create a new reference to the class, such as:我想要一个 self.ID,每次我创建对 class 的新引用时都会自动递增,例如:

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

I know I can reference resource_cl, but I'm not sure how to proceed from there...我知道我可以参考 resource_cl,但我不知道如何从那里开始......

Concise and elegant:简洁优雅:

import itertools

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

Trying the highest voted answer in python 3 you'll run into an error since .next() has been removed.尝试在 python 3 中投票最高的答案你会遇到错误,因为.next()已被删除。

Instead you could do the following:相反,您可以执行以下操作:

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)
        ...

First, use Uppercase Names for Classes.首先,对类使用大写名称。 lowercase names for attributes.属性的小写名称。

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

Using count from itertools is great for this:使用itertools 中的count 非常有用

>>> 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

The same interface works if you later need to change how the values are generated, you just change the definition of id_generator .如果您以后需要更改值的生成方式,则相同的接口可以工作,您只需更改id_generator的定义。

Are you aware of the id function in python, and could you use it instead of your counter idea?你知道 python 中的id 函数吗,你可以用它来代替你的反面想法吗?

class C(): pass

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

You could attach the count to the class as a class parameter, and then on init you're able to copy this value to an instance parameter.您可以将计数作为类参数附加到类,然后在初始化时您可以将此值复制到实例参数。

This makes count a class param, and id an instance param.这使得count成为一个类参数, id成为一个实例参数。 This works because integers are immutable in python, therefore the current value is copied and not the attribute itself.这是有效的,因为整数在 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]

Ids sometimes benefit from using some fields of the object you wanted to reference. Id 有时会受益于使用您想要引用的对象的某些字段。 This is a old style database technique.这是一种旧式的数据库技术。

for example if you have a app that keeps records for incoming customer phone calls, then possible use an id generated by time = some thing else例如,如果您有一个应用程序可以记录客户来电的记录,则可以使用时间生成的 ID = 其他事情

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

only beaware the time.time() and time.clock() are individual computer return value unless on generated on the server.只需要注意 time.time() 和 time.clock() 是单独的计算机返回值,除非在服务器上生成。 And if on the server make sure your server clock is set right;如果在服务器上,请确保您的服务器时钟设置正确; as always.一如既往。

Another note on id() and rethinking other's answer about it.关于 id() 的另一个注释并重新考虑其他人的答案。 id() may return a unique number, if and only if it remembers every id ever returned even if an object is deleted; id() 可能会返回一个唯一的数字,当且仅当它记住每个曾经返回的 id,即使对象被删除; which it (id()) does not do.它 (id()) 不这样做。 So therefore...所以因此...

In support of what others were saying that id() does not return a unique number;支持其他人所说的 id() 不返回唯一数字; It is true that it can not guarentee a unique value if and only if you are storing those id() values as references to objects AND that you are deleting the instances of objects you are getting id()s for.确实,当且仅当您将这些 id() 值存储为对对象的引用并且您正在删除要为其获取 id() 的对象实例时,它确实无法保证唯一值。 BUT !但 ! using id() as a reference means that you basically have an object that has a key linked somehow with another object.使用 id() 作为参考意味着您基本上拥有一个对象,该对象的键以某种方式与另一个对象链接。

This is not invalidated by non-uniqueness of id().这不会因 id() 的非唯一性而无效。 It is only invalidated if you do not check if adding a new object has a preexisting id() already stored as a reference to some other instance of the object.仅当您不检查添加新对象是否已将预先存在的 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 ] returns some other object instance not object3;但是 storeit[4357891223] 返回一些其他的对象实例而不是 object3; therefore the < link > remains valid but the uniqueness fails.因此 < link > 仍然有效但唯一性失败。

I like to use generators for ids.我喜欢使用生成器来生成 id。 Allow the generator to maintain a list of ids already used.允许生成器维护已使用的 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

Although this is not a memory effiecent way for huge in-memory datasets.尽管对于巨大的内存数据集来说,这不是一种高效的内存方式。 If you wanted to use something like that then modify this to have the OS handle caching to a file... say via a named pipe.如果你想使用类似的东西,那么修改它以使操作系统处理缓存到文件......说通过命名管道。

def create_next_id(cnt=0):
    def create_next_id_inner():
        nonlocal cnt
        cnt += 1
        return cnt - 1
    return create_next_id_inner
...
next_id = create_next_id()
...
my_data = {'id': next_id(), ...}
my_data2 = {'id': next_id(), ...}
...

Hello this may be the Lengthy way, But Worked very Fluently for me.您好,这可能是冗长的方式,但对我来说非常流利。 Hope it Helps.希望能帮助到你。 I have done it using a External Text file named id.txt .我使用名为id.txt的外部文本文件完成了它。

Just create an empty file named as above.只需创建一个如上命名的空文件。 Then run this snippet.然后运行这个片段。 That will definitely work.那肯定会奏效。

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

And to get the Value from this Snippet do this.并从该代码段中获取值,请执行此操作。

id = id_generator()

If any of the Reader find it useful, Please pass a Comment and Let me know if my work Paid off.如果任何读者觉得它有用,请通过评论并让我知道我的工作是否得到了回报。

Hope it helps.希望能帮助到你。 Thank You......谢谢......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM