Code incompatibility issues - Python 2.x/ Python 3.x - python-3.x

I have this code:
from abc import ABCMeta, abstractmethod
class Instruction (object):
__metaclass__ = ABCMeta
def __init__(self, identifier_byte):
#type: (int) ->
self.identifier_byte = identifier_byte
#abstractmethod
def process (self):
print ("Identifier byte: ()".format(self.identifier_byte))
class LDAInstruction (Instruction):
def process (self):
super(Instruction,self).process()
with works fine with Python 3.2 but not with 2.6. Then based on this topic: TypeError: super() takes at least 1 argument (0 given) error is specific to any python version?
I changed the last line to:
super(Instruction,self).process()
which causes this error message on this precise line:
AttributeError: 'super' object has no attribute 'process'
For me it seems that there is a "process" method for the super invocation. Is Python saying that "super" is an independent object, unrelated to instruction? If yes, how can I tell it that super shall only invoke the base class constructor?
If not, how I shall proceed? Thanks for any ideas.

You're passing the wrong class to super in your call. You need to pass the class you're making the call from, not the base class. Change it to this and it should work:
super(LDAInstruction, self).process()
It's unrelated to your main error, but I'd further note that the base-class implementation of process probably has an error with its attempt at string formatting. You probably want {0} instead of () in the format string. In Python 2.7 and later, you could omit the 0, and just use {}, but for Python 2.6 you have to be explicit.

Related

How can I type cast a non-primitive, custom class in Python?

How can I cast a var into a CustomClass?
In Python, I can use float(var), int(var) and str(var) to cast a variable into primitive data types but I can't use CustomClass(var) to cast a variable into a CustomClass unless I have a constructor for that variable type.
Example with inheritance.
class CustomBase:
pass
class CustomClass(CustomBase):
def foo():
pass
def bar(var: CustomBase):
if isinstance(var, CustomClass):
# customClass = CustomClass(var) <-- Would like to cast here...
# customClass.foo() <-- to make it clear that I can call foo here.
In the process of writing this question I believe I've found a solution.
Python is using Duck-typing
Therefore it is not necessary to cast before calling a function.
Ie. the following is functionally fine.
def bar(var):
if isinstance(var, CustomClass):
customClass.foo()
I actually wanted static type casting on variables
I want this so that I can continue to get all the lovely benefits of the typing PEP in my IDE such as checking function input types, warnings for non-existant class methods, autocompleting methods, etc.
For this I believe re-typing (not sure if this is the correct term) is a suitable solution:
class CustomBase:
pass
class CustomClass(CustomBase):
def foo():
pass
def bar(var: CustomBase):
if isinstance(var, CustomClass):
customClass: CustomClass = var
customClass.foo() # Now my IDE doesn't report this method call as a warning.

How to write own metaclass?

How to create a metaclass in python? I tried to write as in tutorials:
class Meta(type):
def __new__(mcs, name, bases, attrs):
attrs2 = {'field2': 'Test'}
attrs2.update(attrs)
return super(Meta, mcs).__new__(mcs, name, bases, attrs2)
class Test(object):
__metaclass__ = Meta
field1 = 10
test = Test()
print(test.field1)
print(test.field2)
But this code fails with error:
10
Traceback (most recent call last):
File "main.py", line 18, in <module>
print(test.field2)
AttributeError: 'Test' object has no attribute 'field2'
How to declare a metaclass in python 3.7+ correctly?
UPDATED
I've changed my question with actual error.
The tutorials you are checking are covering Python 2.
In Python 3, one of the syntactic changes was exactly the way of declaring a metaclass for a class.
You don't need to change the metaclass code, just change your class declaration to:
class Test(metaclass=Meta):
field1 = 10
and it will work.
So, in short: for a metaclass in Python 3, you have to pass the equivalent of a "keyword argument" in the class declaration, with the name "metaclass". (Also, in Python 3, there is no need to inherit explicitly from object)
In Python 2, this was accomplished by the presence of the special variable __metaclass__ in the body of the class, as is in your example. (Also, when setting a metaclass, inheriting from 'object' would be optional, since the metaclass, derived from type, would do that for you).
One of the main advantages of the new syntax is that it allows the special method __prepare__ in the metaclass which can return a custom namespace object to be used when building the class body itself. It is seldom used, and a really "serious" use case would be hard to put up today. For toys and playing around, it is great, allowing for "magic autonamed enumerations" and other things - but when designing Python 3, this was way they thought to allow having an OrderedDict as the class namespace, so that the metaclass' __new__ and __init__ methods could know the order of the declaration of the attributes. Since Python 3.6, a class body namespace is ordered by default and there is no need for a __prepare__ method for this use alone.

final annotation and decorator in python3.8

As Python 3.8 releasing soon just wanted to know the difference between The final decorator and The Final annotation.
In Python 3.8 the Python type hinting feature (embodied by the typing module) will support marking names as final. This is documented in PEP 591 – Adding a final qualifier to typing.
What this means is that the typing module gains two new objects:
The typing.Final typing construct
The #typing.final() decorator.
To be up-front: The Python language itself does not gain final syntax or support. The above objects do not alter how Python works, they are constructs that merely document that an object or reference is to be considered final. The new objects can trivially be backported to older Python releases. The typing-extensions project, which provides backports of typing features from later to earlier Python versions, has already included these objects.
Their use lies in using a type hint checker like mypy to check that your project correctly treats the objects so documented as final.
Their use is otherwise exactly like that of the final keyword in Java: to state that a specific reference can only be assigned to once, that a method cannot be overridden in a subclass, or that a class definition cannot be subclassed.
Use the typing.Final object to mark a global or attribute as final, documenting that the value will never change once assigned to:
GLOBAL_CONSTANT: Final[str] = "This is a constant value because it is final"
Use the #typing.final decorator to mark a method as non-overridable (subclasses can't define a different implementation) or a class as non-inheritable (you can't create subclasses from the class):
#final
class FinalClass:
"""This class can't be inherited from"""
class SomeClass:
#final
def final_method(self):
"""Subclasses can't define a different final_method implementation"""
Also see the mypy documentation on their use, which covers such details as to what ways of assigning the value of a Final attribute are acceptable.
Demo:
$ cat demo.py
from typing import final, Final
# FOO is marked final, can't assign another value to it
FOO: Final[int] = 42
class Foo:
#final
def spam(self) -> int:
"""A final method can't be overridden in a subclass"""
return 42
#final
class Bar:
"""A final class can't be subclassed"""
# Rule breaking section
FOO = 81
class Spam(Foo, Bar):
def spam(self) -> int:
return 17
if __name__ == '__main__':
print("FOO:", FOO)
print("Spam().spam():", Spam().spam())
$ python3.8 demo.py # Python will not throw errors here
FOO: 81
Spam().spam(): 17
$ mypy demo.py # only a type checker will
demo.py:17: error: Cannot assign to final name "FOO"
demo.py:19: error: Cannot inherit from final class "Bar"
demo.py:20: error: Cannot override final attribute "spam" (previously declared in base class "Foo")

How to override class attribute access in python3

I am trying to override class attribute access in python3. I found this question already answered for python2. But the same is not working with Python3. Please help me to understand why this does not work with Python3 and how to get it to work.
Here is the code i am trying to verify in Python3:
class BooType(type):
def __getattr__(self, attr):
print(attr)
return attr
class Boo(object):
__metaclass__ = BooType
boo = Boo()
Boo.asd #Raises AttributeError in Python3 where as in Python2 this prints 'asd'
from http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Metaprogramming.html
Python 3 changes the metaclass hook. It doesn’t disallow the __metaclass__ field, but it ignores it. Instead, you use a keyword argument in the base-class list:
in your case, you have to change to:
class Boo(object, metaclass = BooType):
pass
and that works. This syntax isn't compatible with python 2, though.
There's a way to create compatible code, seen in http://python-future.org/compatible_idioms.html#metaclasses
# Python 2 and 3:
from six import with_metaclass
# or
from future.utils import with_metaclass
class Boo(with_metaclass(BooType, object)):
pass

How may I turn a variable assignment into a methodcall in Python 3?

Let's say I have the following classes:
class Constants():
def __init__(self, constant=None):
self.value = constant
# Some magic goes here
class SomeConstants(Constants):
PROJECT_NAME = 'constants'
How can I make that definition turn programatically into
class SomeConstants(Constants):
#staticmethod
def PROJECT_NAME():
return SomeConstants('constants')
so that whenever I call SomeConstants.PROJECT_NAME, SomeConstants.PROJECT_NAME(), SomeConstants().PROJECT_NAME, or SomeConstants().PROJECT_NAME() I get the same result, namely an instance of ProjectConstants, having 'constants' as its value?
Edit
After John Kugelman's comment, I realize that calling SomeConstants.PROJECT_NAME, and getting an instance of ProjectConstants, having 'constants' as its value would be what I am looking for.
The magic method call() may be what you are looking for here.
The Enum class in Python does what I want.
Using enums, require some slight alterations, but for my intent and purposes, it solves the problem.

Resources