Is it okay to write own magic methods? - python

In my web application I often need to serialize objects as JSON.
Not all objects are JSON-serializable by default so I am using my own encode_complex method which is passed to the simplejson.dumps as follows: simplejson.dumps(context, default=self.encode_complex)
Is it okay to define my own magic method called __json__(self) and then use code similar to the following in encode_complex method?
def encode_complex(self, obj):
# additional code
# encode using __json__ method
try:
return obj.__json__()
except AttributeError:
pass
# additional code

The __double_underscore__ names are reserved for future extensions of the Python language and should not be used for your own code (except for the ones already defined, of course). Why not simply call the method json()?
Here is the relevant section from the Python language reference:
__*__
System-defined names. These names are defined by the interpreter and its implementation (including the standard library). Current system names are discussed in the Special method names section and elsewhere. More will likely be defined in future versions of Python. Any use of __*__ names, in any context, that does not follow explicitly documented use, is subject to breakage without warning.

You probably don't want to use double underscore due to name mangling http://docs.python.org/reference/expressions.html#atom-identifiers -- However in concept what you're doing is fine for your own code.

As explained in other answers the double underscores shouldn't be used.
If you want to use a method with a name that implies that is to be used only by the internal implementation, then I suggest to use a single leading underscore.
As explained in PEP 8:
_single_leading_underscore: weak "internal use" indicator. E.g. "from M import *" does not import objects whose name starts with an underscore.

Related

Python Lists and Local List declaration

How to explicitly declare a list as a local variable that cannot be touched from anywhere except the function its declared in?
tried
LOCAL variable = []
doesnt work
Python is the interpreted language and it hasn't such statements.
Here is from the documentation:
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice
You can notice such _pseudo_private_var(one underscore) naming.It is just a convention, it just tells you SHOUDN'T touch this variable but you CAN change value of this one at the same time. It is a python). There is __dynamic_obj_relative_naming as well(two underscores).
More about scopes and namespaces rules you could find here Classes, namespace and scope rules. There are few interesting statements you are interested in probably global and nonlocal. They are like opposites of yours.

Name not defined in type annotation [duplicate]

This question already has answers here:
How do I type hint a method with the type of the enclosing class?
(7 answers)
Closed 3 years ago.
I'm currently working on creating a python linear algebra module for fun and for practice with the language. I recently tried to add type annotations to the module, as such:
class Vector:
# Various irrelevant implementation details
def __add__(self, other: Vector) -> Vector:
# More implementation details....
However, when I try to import this, it spits out a NameError: Name 'Vector' is not defined. I acknowledge that this question has already been answered, in a form, here, but it doesn't seem to wholly provide an answer for my situation.
What I'd like to know:
I've defined the class literally in this file. Why does it say the name isn't defined?
How do I define Vector in such a way that it can be used for annotations (as a type)?
You have a forward declaration; functions (to be bound as methods) are created before the class is, so the name Vector doesn't yet exist. Only when all of the class body has been executed, can Python create the class object and bind the name Vector to it.
Simply use a string with the name instead:
class Vector:
# Various irrelevant implementation details
def __add__(self, other: 'Vector') -> 'Vector':
# More implementation details....
This doesn't affect how your IDE sees the declaration; strings are looked up once the whole module is loaded, and are resolved as a valid Python expression in the current context. Since the class Vector exists once the whole module is loaded, the string 'Vector' can properly be converted to the class object.
Also see the specification on forward references:
When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.
[...]
The string literal should contain a valid Python expression [...] and it should evaluate without errors once the module has been fully loaded.
As of Python 3.7 you can make all annotations in a given module behave like forward annotations (without enclosing them in a string literal), by adding the from __future__ import annotations directive at the top of the module. It was originally planned for this to be the default in Python 3.10 and up, but this decision has now been deferred indefinitely. See PEP 563 -- Postponed Evaluation of Annotations for details. Note that outside of annotations you may still need to use forward reference syntax (string literals), e.g. in a type alias (which is a regular variable assignment as far as Python is concerned).
If you are using Python 3.7 and above. Take a look at Postponed evaluation of annotations
Since Python 3.7, it will be allowed, just add:
from __future__ import annotations
And also note that
It will become the default in Python 3.10.

How to specify docstring for __init__ in Python C extension

Perhaps a stupid question:
how can one specify docstring for special functions like __init__ when writing a C extension?
For ordinary methods, method table has provision for docstrings. The following autogenerated documentation is displayed when I try help(myclass):
__init__(...)
x.__init__(...) initializes x; see help(type(x)) for signature
But this is what I want to override.
I think that the most common thing to do is to just stick the definitions for the various functions into tp_doc and just leave it at that. You can then do as it says and look at your object's doc. This is what happens all over the standard library.
You don't really have any option of writing __doc__ on the various slots (tp_init, etc.) because they're wrapped by a wrapper_descriptor when you call PyType_Ready, and the docstring on a wrapper_descriptor is read-only.
I think that it is possible to skip using the slots and add your method (e.g. __init__) to your MemberDefs, but I've never tried that.

Significance of double underscores in Python filename

Other than for __init__.py files, do the leading and trailing double underscores have any significance in a file name? For example, is __model__.py in any way more significant than model.py?
Double underscores in filenames other than __init__.py and __main__.py have no significance to Python itself, but frameworks may use them to indicate/identify various things.
Ahhh! I see you've discovered magic methods.
The double underscores are called "dunder" and they invoke special methods which can have some really neat effects on objects. They don't change significance, but they are pretty amazing voodoo, and a good tool to have on your belt.
Here's a link of many links, I learned all about magic methods through here.
http://pythonconquerstheuniverse.wordpress.com/2012/03/09/pythons-magic-methods/
__init__ is a magic method for declaring stuff to happen on initialization of an object. It only preceded by __new__.
The most useful of these methods I've been using is the __dict__ method. The __dict__ method makes it so that all attributes in a class turn into key value pairs that can then be used like a dictionary. Although I don't think using it as a file name would be useful.
here's an example:
class Thing(object):
def __init__(self): ##Init here is a magic method that determines what haps first
self.tint = "black"
self.color = "red"
self.taste = "tangy"
thing = Thing()
dictionary_from_class = {}
for key in thing.__dict__.keys(): ##returns all key values. here: "tint, color, taste"
dictionary_from_class[key] = thing.__dict__[key]
Fire up Idle in python, and try that out. Good luck in practicing python voodoo!
EDITED
Sorry, I really quickly read your question, let me mention this because I may have not covered it in my answer: If the filename is __init__.py, it does a similar thing, to what I mention before. It invokes the Initialization, and python will do that stuff as soon as the folder is reached for module usage. That is if you are reading off that file because it was called, such as referring to a folder of modules, and in that case you NEED a __init__.py file just to get python to recognize it inside the folder. You can use any of the magic methods as names to get a similar functionality upon usage.
I hope that clarification was useful.
-Joseph

Is it a convention to prefix private classes with underscores?

I have seen code in which functions/constants are prefixed with underscores.
My understanding is that this indicates that they are not to be used directly.
Can I do this with classes ?
class _Foo(object):
pass
class __Bar(object):
pass
Better only use one _. This indicates that a name is private within a module.
It is not imported with the catch-all from <module> import *, and it has some other features such as "preferred destruction".
From here:
If __all__ is not defined, the set of public names includes all names
found in the module’s namespace which do not begin with an underscore
character ('_').
From here:
Starting with version 1.5, Python guarantees that globals whose name begins with a
single underscore are deleted from their module before other globals are deleted.
Double-underscore starting class members are name-mangled.
Yes; the single underscore usage is endorsed by PEP8 for internal-use classes.
I don't believe the double underscore usage will have any real effect most of the time, since it's used to active name mangling for class attributes, and generally a class isn't an attribute of another class (granted, it can be, in which case Python will happily mangle the name for you.)
Yes, and this is not only a convention. When you import * from this module, names starting with underscore will not be imported.
You can use a single underscore as the first character in any variable, but it is carries the implied meaning, "Do not use outside of the class/module unless you really know what you're doing" (eg. intended protected/internal) and it will not import if you use from <module> import *.
Using a double underscore is something you should never do outside of a class as it could mess with name mangling otherwise (and by "could", I mean, "caused me a big headache this past week because I did not realize that it does").

Categories

Resources