There are several interacting considerations here:
- failure inside
__init__fails to construct the object - re-use of code
- clear organisation and documentation of code
- minor code differences such as using an attribute instead of a local
Separation of create_snake into it's own method (#3), with a name that documents it's purpose, clarifies and organises the code to make it quicker to understand and modify and potentially more robust (in principle, possibly of negligible difference in this case). Identifier names are arguably the single most important element of code documentation, in this case "create snake". I think this is a good argument for using snake case identifiers.
At this point in the development there's no indication whether create_snake will be called at any other time for this object, but if later you do need to create_snake again, for the same object, this separation of the create_snake code keeps it DRY (#2).
In Python, __init__ always returns None. It's not a "proper" method from that point of view. Any failures inside the __init__ method will mean the object is not created, potentially requiring a try...except wrapper (#1). Work should be minimised within __init__ (#1) for this reason.
In your implementation here, moving the code out into create_snake doesn't actually fix that, because it's still called from __init__. This can be improved by calling create_snake after the object is created, but that slightly complicates the usage pattern, and may not be justified in this instance (depends on your planning).
(The reason I found this question in the first place was because I was seeking clarification of a vague memory I have of some article arguing that doing work inside __init__ is an anti-pattern.)
To take this concept even further, you can create a practically empty object, and leave snake creation, and any other work, to lazy methods that are only called when needed. You can find further discussion on approaches.
There are other code considerations that may possibly be incidental to your core question (#4). For instance, there's no point in using an instance attribute (self.snake_segment) when you never use that value after the method completes, because it just makes the object heavier and requires more variable look-ups. Depending on your wider code organisation, it may also be better to keep class related constants (STARTING_POSITIONS) inside the class, rather than at the module level. I'm not stating that is the case for you; it depends very much on what your wider code is doing.
As an overall answer I'd say that your second approach is definitely better, and most probably good enough as well.
Answer from NeilG on Stack OverflowI wrote a Snake game in pure Python!
what are constructors in python?
Videos
There is no function overloading in Python, meaning that you can't have multiple functions with the same name but different arguments.
In your code example, you're not overloading __init__(). What happens is that the second definition rebinds the name __init__ to the new method, rendering the first method inaccessible.
As to your general question about constructors, Wikipedia is a good starting point. For Python-specific stuff, I highly recommend the Python docs.
Why are constructors indeed called "Constructors" ?
The constructor (named __new__) creates and returns a new instance of the class. So the C.__new__ class method is the constructor for the class C.
The C.__init__ instance method is called on a specific instance, after it is created, to initialise it before being passed back to the caller. So that method is the initialiser for new instances of C.
How are they different from methods in a class?
As stated in the official documentation __init__ is called after the instance is created. Other methods do not receive this treatment.
What is their purpose?
The purpose of the constructor C.__new__ is to define custom behaviour during construction of a new C instance.
The purpose of the initialiser C.__init__ is to define custom initialisation of each instance of C after it is created.
For example Python allows you to do:
class Test(object):
pass
t = Test()
t.x = 10 # here you're building your object t
print t.x
But if you want every instance of Test to have an attribute x equal to 10, you can put that code inside __init__:
class Test(object):
def __init__(self):
self.x = 10
t = Test()
print t.x
Every instance method (a method called on a specific instance of a class) receives the instance as its first argument. That argument is conventionally named self.
Class methods, such as the constructor __new__, instead receive the class as their first argument.
Now, if you want custom values for the x attribute all you have to do is pass that value as argument to __init__:
class Test(object):
def __init__(self, x):
self.x = x
t = Test(10)
print t.x
z = Test(20)
print t.x
I hope this will help you clear some doubts, and since you've already received good answers to the other questions I will stop here :)
Hi everyone,
I'm a grad student who's been learning/using Python for about two years now. As a "toy project" to challenge myself, I've put together a Snake game in pure Python - no dependencies, no pygame, only the standard library. I know it's small, and it's been done a thousand times over, but I'm proud of how it has turned out.
Python was my first programming language ever, which I decided to learn out of the need for automation in my PhD analyses. I've since fallen in love with programming and data analysis. Hopefully this will encourage some of you to keep on learning :-) don't give up!
Feel free to see it in action and get the code here:
https://github.com/jfaccioni/python-snake-game
its pretty confusing especially the ``def __init__`` one what does it exactly do? can anyone help me