FAQ
Hi

I have searched all over and haven't found the solution
for my problem yet. I am new to python, and all the time realize I
do program python in java, which is not great.

Besides being a real-life problem, I want to
solve it as elegant as I can, using it to
also learn about python (I know I could just
hack something easy for now).

That's what I want to do.

I have an Account class.
An Account instance has to get an account number.
On instance creation, I want the account number to
be generated (I don't want callers to pass
the account # to ensure uniqueness):

class Account(object):
def __init__(self, holder):
self.__accountnumber = self.__generate_account_number()

Now, I do not know yet how the account number scheme looks like.
For now, I just want to have an incremental number; later,
when going to production, we'll need the proper one.

Furthermore, as we plan to distribute the package, we want
to allow custom account numbering schemes. Thus, customers
should be able to plug in their own AccountNumberGenerator implementation.

For now, I have a generators.py module.

I have an AccountNumberGenerator base class,
all subclasses should implement "generate".

I have an IncrementalGenerator subclass.

So for now, I need to instantiate IncrementalGenerator,
allowing for a future module to plugin their own generator.

Any suggestions on how to do this?
Thanks so much!!!!

Search Discussions

  • Stefan Behnel at Jul 14, 2009 at 2:27 pm

    phonky wrote:
    class Account(object):
    def __init__(self, holder):
    self.__accountnumber = self.__generate_account_number()

    Now, I do not know yet how the account number scheme looks like.
    For now, I just want to have an incremental number; later,
    when going to production, we'll need the proper one.
    Use a global variable in the module.

    Stefan

    From http Tue Jul 14 16:33:26 2009
    From: http (Paul Rubin)
    Date: 14 Jul 2009 07:33:26 -0700
    Subject: one-time factory in python for an experienced java guy
    References: <b2094$4a5c9024$d9a2f023$3278@news.hispeed.ch>
    <4a5c95e4$0$31340$9b4e6d93@newsspool4.arcor-online.net>
    Message-ID: <7xzlb7wczt.fsf@ruckus.brouhaha.com>

    Stefan Behnel <stefan_ml at behnel.de> writes:
    phonky wrote:
    class Account(object):
    def __init__(self, holder):
    self.__accountnumber = self.__generate_account_number()

    Now, I do not know yet how the account number scheme looks like.
    For now, I just want to have an incremental number; later,
    when going to production, we'll need the proper one.
    Use a global variable in the module.
    Yuch! Don't use a global. Try something like:

    import itertools

    class Account(object):
    def __init__(self, holder, gen=itertools.count()):
    self.__accountnumber = gen.next()
  • Phonky at Jul 14, 2009 at 2:34 pm
    Stefan, thanks first of all
    Use a global variable in the module.
    I have an account_number_generator variable in the module,
    I got that hint from searching the web.

    But where my stubborn java mind doesn't release me:
    what does the variable contain? Do I create the actual
    IncrementalGenerator object there? Or the super class?
    Or just a string, which a factory method takes to
    create the actual object?

    What I especially don't get:
    How will an external module overwrite that variable?

    I fail to see, python being interpreted, how I can ensure
    that a future module is being executed later, thus
    overwriting the variable.

    Thanks again.


    From http Tue Jul 14 16:40:52 2009
    From: http (Paul Rubin)
    Date: 14 Jul 2009 07:40:52 -0700
    Subject: one-time factory in python for an experienced java guy
    References: <b2094$4a5c9024$d9a2f023$3278@news.hispeed.ch>
    <4a5c95e4$0$31340$9b4e6d93@newsspool4.arcor-online.net>
    <f2017$4a5c9776$d9a2f023$27613@news.hispeed.ch>
    Message-ID: <7xab37l43v.fsf@ruckus.brouhaha.com>

    phonky <phonky at europe.com> writes:
    But where my stubborn java mind doesn't release me: what does the
    variable contain? Do I create the actual IncrementalGenerator object
    there? Or the super class? Or just a string, which a factory method
    takes to create the actual object?
    Ugh, just forget everything you ever knew about java. Do some Zen
    exercises to erase your mind. Then read a Python tutorial as if
    you're starting from nothing.
  • Phonky at Jul 14, 2009 at 2:55 pm
    Thanks Paul,
    Ugh, just forget everything you ever knew about java. Do some Zen
    exercises to erase your mind. Then read a Python tutorial as if
    you're starting from nothing.
    Yeah, surely right, but easier said than done...
    I'm working on it.

    Taking your example.

    import itertools

    class Account(object):
    def __init__(self, holder, gen=itertools.count()):
    self.__accountnumber = gen.next()

    If you consider my python illiteracy,

    "itertools.count(): Make an iterator that returns consecutive integers
    starting with n"

    to me that sounds like that solves the increment issue, but what about
    future modules wanting to plug in a different
    numbering format, e.g. 205434.1234 or whatever?
  • Mahmoud Abdelkader at Jul 14, 2009 at 3:07 pm
    What Paul was trying to elaborate on is that have your customers or whomever
    will use this implement their own generator protocol to generate whatever
    number format they need. Paul just gave you an example with
    itertools.count(), where it is an infinite generator that yields count+1
    every time.

    Read up on the iterator protocol, have your customers pass in a generator to
    establish their own formats.
    http://docs.python.org/library/stdtypes.html#iterator-types

    This is much more elegant than AbstractCustomerRandomFormatGenerator..etc
    which is what the reference to "erase everything from Java" is attempting to
    relate.

    --
    mahmoud mack abdelkader
    python powered
    http://blog.mahmoudimus.com/
    mahmoud at linux.com

    On Tue, Jul 14, 2009 at 10:55 AM, phonky wrote:

    Thanks Paul,

    Ugh, just forget everything you ever knew about java. Do some Zen
    exercises to erase your mind. Then read a Python tutorial as if
    you're starting from nothing.
    Yeah, surely right, but easier said than done...
    I'm working on it.

    Taking your example.

    import itertools

    class Account(object):
    def __init__(self, holder, gen=itertools.count()):
    self.__accountnumber = gen.next()

    If you consider my python illiteracy,

    "itertools.count(): Make an iterator that returns consecutive integers
    starting with n"

    to me that sounds like that solves the increment issue, but what about
    future modules wanting to plug in a different
    numbering format, e.g. 205434.1234 or whatever?



    --
    http://mail.python.org/mailman/listinfo/python-list
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20090714/d8becbaf/attachment.htm>
  • Peter Otten at Jul 14, 2009 at 3:20 pm

    phonky wrote:

    Thanks Paul,
    Ugh, just forget everything you ever knew about java. Do some Zen
    exercises to erase your mind. Then read a Python tutorial as if
    you're starting from nothing.
    Yeah, surely right, but easier said than done...
    I'm working on it.

    Taking your example.

    import itertools

    class Account(object):
    def __init__(self, holder, gen=itertools.count()):
    self.__accountnumber = gen.next()

    If you consider my python illiteracy,

    "itertools.count(): Make an iterator that returns consecutive integers
    starting with n"

    to me that sounds like that solves the increment issue, but what about
    future modules wanting to plug in a different
    numbering format, e.g. 205434.1234 or whatever?
    In that case you may want to stick with the class attribute:
    class Account(object):
    ... def __init__(self):
    ... self.account = self.next_account()
    ... def __str__(self):
    ... return "Account(number=%r)" % self.account
    ... __repr__ = __str__
    ...
    from itertools import count
    Account.next_account = count(42).next
    a = Account()
    b = Account()
    a, b
    (Account(numberB), Account(numberC))
    from uuid import uuid1
    Account.next_account = staticmethod(uuid1)
    c = Account()
    d = Account()
    c, d
    (Account(number=UUID('b0f8dfc6-7087-11de-be16-001d923f29c5')),
    Account(number=UUID('b310c90e-7087-11de-be16-001d923f29c5')))

    You can plug in arbitrary callables at runtime. The only complication I can
    see is that you may have to wrap them into a staticmethod to prevent python
    from passing the self reference. You can avoid that if you just use a global
    instead:

    # account.py
    next_account = ...
    class Account(object):
    def __init__(self): self.number = next_account()

    You can then set the factory elsewhere

    # main.py
    import account
    account.next_account = ...
    a = Account()

    In general in python we like to keep simple things simple rather than
    creating a huge bureaucracy.

    Peter
  • Aahz at Jul 14, 2009 at 3:24 pm
    In article <23406$4a5c9c7d$d9a2f023$27926 at news.hispeed.ch>,
    phonky wrote:
    import itertools

    class Account(object):
    def __init__(self, holder, gen=itertools.count()):
    self.__accountnumber = gen.next()

    If you consider my python illiteracy,

    "itertools.count(): Make an iterator that returns consecutive integers
    starting with n"

    to me that sounds like that solves the increment issue, but what about
    future modules wanting to plug in a different
    numbering format, e.g. 205434.1234 or whatever?
    Here's what I would do:

    class Account:
    gen = itertools.count
    gen_instance = None

    def __init__(self, holder):
    if self.gen_instance is None:
    self.__class__.gen_instance = self.gen()
    self._account = self.gen_instance()

    Notice that I'm using only a single underscore for ``_account`` to make
    inheritance simpler, and I'm using ``self`` to access class attributes
    *except* when I need to *set* the class attribute, which requires
    ``self.__class__``.

    Now anyone who wants to change the generator can simply do
    module.Account.gen = other_gen
    and it will work as long as no Account() instances have been created (you
    don't want the generator to change mid-stream, right?).
    --
    Aahz (aahz at pythoncraft.com) <*> http://www.pythoncraft.com/

    "If you think it's expensive to hire a professional to do the job, wait
    until you hire an amateur." --Red Adair
  • Pdpi at Jul 14, 2009 at 3:35 pm

    On Jul 14, 3:03?pm, phonky wrote:
    Hi

    I have searched all over and haven't found the solution
    for my problem yet. I am new to python, and all the time realize I
    do program python in java, which is not great.

    Besides being a real-life problem, I want to
    solve it as elegant as I can, using it to
    also learn about python (I know I could just
    hack something easy for now).

    That's what I want to do.

    I have an Account class.
    An Account instance has to get an account number.
    On instance creation, I want the account number to
    be generated (I don't want callers to pass
    the account # to ensure uniqueness):

    class Account(object):
    ? ? ? ? def __init__(self, holder):
    ? ? ? ? ? ? ? ? self.__accountnumber = self.__generate_account_number()

    Now, I do not know yet how the account number scheme looks like.
    For now, I just want to have an incremental number; later,
    when going to production, we'll need the proper one.

    Furthermore, as we plan to distribute the package, we want
    to allow custom account numbering schemes. Thus, customers
    should be able to plug in their own AccountNumberGenerator implementation.

    For now, I have a generators.py module.

    I have an AccountNumberGenerator base class,
    all subclasses should implement "generate".

    I have an IncrementalGenerator subclass.

    So for now, I need to instantiate IncrementalGenerator,
    allowing for a future module to plugin their own generator.

    Any suggestions on how to do this?
    Thanks so much!!!!
    You don't want an AccountNumberGenerator class and subclassing, all
    you need is an iterator/generator of some form.

    These might help:
    http://docs.python.org/tutorial/classes.html#iterators
    http://docs.python.org/tutorial/classes.html#generators
    (in fact, that whole page is pretty relevant)

    Once your code expects one of those, it's trivially easy to plug
    something else in there.
  • Phonky at Jul 14, 2009 at 5:50 pm
    Thanks for all replies.

    I need to practice much more pythonese....
    In fact I don't think to understand all
    of your suggestions, so I'll need to
    go through them and decide what approach I am going
    to take.

    Thanks a lot!
  • Jonathan Gardner at Jul 14, 2009 at 8:05 pm

    On Jul 14, 7:03?am, phonky wrote:
    Now, I do not know yet how the account number scheme looks like.
    Exactly. The data store knows a lot more than the client (your
    program) will ever know.

    The correct answer is to do nothing. Use your data store to generate
    the IDs for you. The implementations discussed here will not generate
    unique IDs across invocations, but the data store will persist the
    sequence for you appropriately.

    The more correct answer is to abstract away the client to your data
    store as well. See SQLAlchemy.

    If you're writing a data store, you're doing it wrong. See PostgreSQL,
    MySQL, or any other data store out there that are perfectly fine for
    development and production use.

    I like to use UUIDs for the IDs. Others like big ints that are a
    sequence. I've seen people use encrypted big ints, basically random
    strings that aren't really random. In the end, you only have to change
    the code that talks to the data store, and the rest of your program
    only cares about the equality of the id.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJul 14, '09 at 2:03p
activeJul 14, '09 at 8:05p
posts10
users7
websitepython.org

People

Translate

site design / logo © 2022 Grokbase