patternpythonMinor
A convenient wrapper for Telegram Bot library
Viewed 0 times
bottelegramconvenientwrapperforlibrary
Problem
I'm working on several projects involving Telegram bots and I've decided to make a library that meets my needs. Basically, there is already a Python library for Telegram bots (
In terms of functionality it works fine. But I'm a self-educated programmer, so I realize that my code often lacks consistency and readability. That's why I'm here, looking for advices on how to understand how to write the code efficiently.
Any critique is welcome, regarding formatting, more efficient and fast code flow, or whatever; and here are the specific questions that concern me:
import telegram in my code), but I wanted to wrap it to make it even more convenient to me.In terms of functionality it works fine. But I'm a self-educated programmer, so I realize that my code often lacks consistency and readability. That's why I'm here, looking for advices on how to understand how to write the code efficiently.
Any critique is welcome, regarding formatting, more efficient and fast code flow, or whatever; and here are the specific questions that concern me:
- I use PyCharm and it suggests me to make some methods in class static. For example,
breakLongMessage(),isDocument(),isPhoto(). As I understand, it is because they don't use anything from within the class, so they are instance-independent (I might be wrong). Is making them@staticmethodreally beneficial? Maybe, memory usage is better?
- I can pass several functions to my main loop, specified in
start(). Their roles are described in the code (I hope I wrote it fine). But sometimes I may not need, for example,termination_function. I thought about passingNoneas a default parameter, butNoneis not callable, so I pass an emptydummyFunctionwhich does nothing. Maybe I can do it better somehow instead?
- There is a
MAX_CHARS_PER_MESSAGEparameter which I want to remain constant. But I had an urge to put it into the class as a static variable. Is it an acceptable practice to use global variables from outside a class in the class?
- Errors happen, and my code handles them and prints them. But I need a way for it to print detailed data on an error. I mean, when I run a code in terminal and it encounters an error (outside
try...except...), it prints it in a very detailed manner, with a full tree of functions, files and line numbers leading to the error. I've been browsing the web and the best I
Solution
Just answering your numbered questions.
-
Static methods are necessary in languages like Java where everything has to be part of a class. But in Python you can just write a function, and so
-
The reasons for preferring this, even though the implementation has to be slightly more wordy, are (i) it's very common in Python for optional arguments to default to
See for example
target is the callable object to be invoked by the
-
Since
This keeps related code together, improves the documentation, and makes the function easier to test (because you can pass in small values for
-
Use the
-
The reason why it's good to keep statements on separate lines is because many Python introspection tools use line numbers. (i) Python stack traces only tell you the line number where the exception happened, so if there are multiple statements on a line, you won't know which one raised the exception; (ii) the Python debugger only lets you set a breakpoint on the first statement on a line, so that if you write
But, in this particular case, instead of:
you can write:
-
The
The double underscore prefix has a particular use case: to allow a class to be sure that a method name won't collide with a method name in some other class, when the two classes are combined via inheritance. If this use case doesn't apply to you, then don't use the double underscore. (The double underscore doesn't make the method private: it just causes the compiler to translate the name so that it's unique; you can still call it via its transformed name.)
-
There's no standard format for docstrings. There are several tools that automatically process docstrings into documentation (pydoc, autodoc, doxygen, etc.), and they have different formats. Use the format for your preferred documentation-processing tool.
-
Yes, it's a good idea to document the types of function arguments and results.
-
There's nothing wrong with using
Like you, I use
So, if you hear someone make-up a new "best practice" proscribing
-
Static methods are necessary in languages like Java where everything has to be part of a class. But in Python you can just write a function, and so
@staticmethod is never necessary, and rarely helpful.-
dummyFunction is fine, but I think many Python programmers would prefer to use None as the default value and write:if periodicFunction is not None:
periodicFunction()The reasons for preferring this, even though the implementation has to be slightly more wordy, are (i) it's very common in Python for optional arguments to default to
None, and so this is easier for the reader to understand; (ii) sometimes you need to explicitly request the default behaviour, and then it's easy to supply the None.See for example
threading.Thread, where:target is the callable object to be invoked by the
run() method. Defaults to None, meaning nothing is called.-
Since
MAX_CHARS_PER_MESSAGE is only used by breakLongMessage, it would be simplest to make it an optional argument to that function:def breakLongMessage(msg, max_len=2048):
"""Split the string msg into pieces that are no longer than
max_len and return them as a list.
"""This keeps related code together, improves the documentation, and makes the function easier to test (because you can pass in small values for
max_len to keep the tests and their results readable).-
Use the
traceback module to format stack traces.-
The reason why it's good to keep statements on separate lines is because many Python introspection tools use line numbers. (i) Python stack traces only tell you the line number where the exception happened, so if there are multiple statements on a line, you won't know which one raised the exception; (ii) the Python debugger only lets you set a breakpoint on the first statement on a line, so that if you write
if condition: statement, then you won't be able to set a breakpoint on statement; (iii) Python tracing, profiling and coverage tools are line-based.But, in this particular case, instead of:
if update.message.document: return True
else: return Falseyou can write:
return bool(update.message.document)-
The
_ and __ prefixes don't have anything to do with the concepts of public and private in languages like Java. All methods in Python are public, but there's a convention whereby an initial single underscore is used to mean "method that's not intended for use outside of the class". But it's just a convention: the language itself does nothing to enforce it.The double underscore prefix has a particular use case: to allow a class to be sure that a method name won't collide with a method name in some other class, when the two classes are combined via inheritance. If this use case doesn't apply to you, then don't use the double underscore. (The double underscore doesn't make the method private: it just causes the compiler to translate the name so that it's unique; you can still call it via its transformed name.)
-
There's no standard format for docstrings. There are several tools that automatically process docstrings into documentation (pydoc, autodoc, doxygen, etc.), and they have different formats. Use the format for your preferred documentation-processing tool.
-
Yes, it's a good idea to document the types of function arguments and results.
-
There's nothing wrong with using
while True: and break. Here's Raymond Hettinger on the subject:Like you, I use
while True often. We use it frequently in the standard library and have no PEP 8 admonition against it, nor does pychecker report it as a negative practice. The use of while 1 loops has a long history in other languages as well.So, if you hear someone make-up a new "best practice" proscribing
while True, just smile and continue to write programs as you have been. You will not be alone. Many excellent programmers write while True whenever it is called for.Code Snippets
if periodicFunction is not None:
periodicFunction()def breakLongMessage(msg, max_len=2048):
"""Split the string msg into pieces that are no longer than
max_len and return them as a list.
"""if update.message.document: return True
else: return Falsereturn bool(update.message.document)Context
StackExchange Code Review Q#117697, answer score: 2
Revisions (0)
No revisions yet.