class UpperAttrMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs["b"] = 77
return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, attrs)
class Cls(object):
__metaclass__ = UpperAttrMetaclass
f = Cls()
print(f.b)
I tried to run this code on Python 3.4.3 and 2.7.11.
In 2.7.11 it works well(output - 77), but 3.4.3 throw Attribute Error
Here is the output (3.4.3)
Traceback (most recent call last):
File "D:/LABS/BSUIR_labs/4cem/PYTHON/lab2/meta.py", line 8, in <module>
print(f.b)
AttributeError: 'Cls' object has no attribute 'b'
Process finished with exit code 1
How can I fix this? metaclasses works in different way??
In python3, you declare the metaclass inline:
class Cls(object, metaclass=UpperAttrMetaclass):
...
I think that 2to3 should handle this, but if you need to support both in the same source file without using 2to3, then you'll probably want some sort of shimming library. six is the de-facto standard here. You'll want to use six.with_metaclass:
import six
class Cls(six.with_metaclass(UpperAttrMetaclass, object)):
...
Related
I'm trying to import a module (module_name.py) that I've created using __import__()
but am seeing the following error:
Traceback (most recent call last):
File "test.py", line 80, in <module>
testImportMethod()
File "test.py", line 68, in testImportMethod
m = __import__("module_name")
File "/dir/module_name.py", line 147
def insert_model(model: MyModel):
^
SyntaxError: invalid syntax
module_name.py has the following code:
class MyModel(object):
property1 = None
property2 = None
class ThingDAO(object):
#staticmethod
def get_thing_by_id(id):
...
#staticmethod
def insert_model(model: MyModel):
...
Why does the import process have a problem with typed parameters?
It's not the import process that has problems with typed parameters. The problem is that typed parameters were added in Python 3.5 (PEP 484) and raise such SyntaxErrors for example on Python 2.7.
Likely (given the SyntaxError) you're using an older version of Python and to make it work you either have to install and use a newer Python version or use on of the workarounds mentioned in the PEP, for example:
class MyModel(object):
property1 = None
property2 = None
class ThingDAO(object):
#staticmethod
def get_thing_by_id(id):
pass
#staticmethod
def insert_model(model):
# type: (MyModel) -> None
pass
class UpperAttrMetaclass(type):
var = "test"
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
print("hello world")
uppercase_attr = {}
for name, val in future_class_attr.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
# reuse the type.__new__ method
# this is basic OOP, nothing magic in there
return type.__new__(upperattr_metaclass, future_class_name,
future_class_parents, uppercase_attr)
class Hello(object):
__metaclass__ = UpperAttrMetaclass
bar = "test"
obj = Hello()
print(obj.BAR) # obj has no attribute named BAR
Traceback (most recent call last):
File "E:\python\test.py", line 32, in
print(obj.BAR)
AttributeError: 'Hello' object has no attribute 'BAR'
Why metaclass UpperAttrMetaclass does not work?
In Python3 the way to specify a metaclass has changed from Python2 in an incompatible way.
Since Python 3.0, the way to specify a metaclass is to use the metaclass name as if it were a Named parameter on the class statement itself.
Thus, in the above example, you shuld declare your Hello class as:
class Hello(metaclass=UpperAttrMetaclass):
bar = "test"
Check the documentation at: https://docs.python.org/3.0/whatsnew/3.0.html#changed-syntax
Besides that, as you've noted, putting a __metaclass__ attribute in a c alss body is not an error, but it does nothing at all, but declaring an attribute with that name.
After a couple releases of Python3.x versions, this is the only syntactic change that is incompatible with Python 2 and can't be work-around in a straightforward way so that the code is both Python 2.x and Python 3.x compatible at the same time.
If you need the same code base to run on Python 2 and Python 3, the package named six brings the call with_metaclass which builds a dynamic class base with a syntax that is compatible with both versions.
(https://pythonhosted.org/six/#syntax-compatibility)
I try to create interface with #staticmethod and #classmethod. Declaring class method is simple. But I can't find the correct way to declare static method.
Consider class interface and its implementation:
#!/usr/bin/python3
from zope.interface import Interface, implementer, verify
class ISerializable(Interface):
def from_dump(slice_id, intex_list, input_stream):
'''Loads from dump.'''
def dump(out_stream):
'''Writes dump.'''
def load_index_list(input_stream):
'''staticmethod'''
#implementer(ISerializable)
class MyObject(object):
def dump(self, out_stream):
pass
#classmethod
def from_dump(cls, slice_id, intex_list, input_stream):
return cls()
#staticmethod
def load_index_list(stream):
pass
verify.verifyClass(ISerializable, MyObject)
verify.verifyObject(ISerializable, MyObject())
verify.verifyObject(ISerializable, MyObject.from_dump(0, [], 'stream'))
Output:
Traceback (most recent call last):
File "./test-interface.py", line 31, in <module>
verify.verifyClass(ISerializable, MyObject)
File "/usr/local/lib/python3.4/dist-packages/zope/interface/verify.py", line 102, in verifyClass
return _verify(iface, candidate, tentative, vtype='c')
File "/usr/local/lib/python3.4/dist-packages/zope/interface/verify.py", line 97, in _verify
raise BrokenMethodImplementation(name, mess)
zope.interface.exceptions.BrokenMethodImplementation: The implementation of load_index_list violates its contract
because implementation doesn't allow enough arguments.
How should I correctly declare static method in this interface?
Obviously the verifyClass does not understand either classmethod or staticmethod properly. The problem is that in Python 3, if you do getattr(MyObject, 'load_index_list') in Python 3, you get a bare function, and verifyClass thinks it is yet another unbound method, and then expects that the implicit self be the first argument.
The easiest fix is to use a classmethod there instead of a staticmethod.
I guess someone could also do a bug report.
Can I dynamically add attributes to instances of a new-style class (one that derives from object)?
Details:
I'm working with an instance of sqlite3.Connection. Simply extending the class isn't an option because I don't get the instance by calling a constructor; I get it by calling sqlite3.connect().
Building a wrapper doesn't save me much of the bulk for the code I'm writing.
Python 2.7.1
Edit
Right answers all. But I still am not reaching my goal; instances of sqlite3.Connection bar my attempts to set attributes in the following ways (as do instances of object itself). I always get an AttributeError:
> conn = sqlite3.connect([filepath])
> conn.a = 'foo'
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
conn.a = 'foo'
AttributeError: 'object' object has no attribute 'a'
> conn.__setattr__('a','foo')
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
conn.__setattr__('a','foo')
AttributeError: 'object' object has no attribute 'a'
Help?
Yes, unless the class is using __slots__ or preventing attribute writing by overriding __setattr__, or an internal Python class, or a Python class implemented natively (usually in C).
You can always try setting an attribute. Except for seriously weird __setattr__ implementations, assigning an attribute to an instance of a class of one of the types mentioned above should raise an AttributeError.
In these cases, you'll have to use a wrapper, like this:
class AttrWrapper(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, n):
return getattr(self._wrapped, n)
conn = AttrWrapper(sqlite3.connect(filepath))
Simple experimentation:
In []: class Tst(object): pass
..:
In []: t= Tst()
In []: t.attr= 'is this valid?'
In []: t.attr
Out[]: 'is this valid?'
So, indeed it seems to be possible to do that.
Update:
But from the documentation: SQLite is a C library that ..., so it seems that you really need to wrap it.
conn.a = 'foo',
or any dynamic assignment is valid, if conn is
<type 'classobj'>.
Things like:
c=object()
c.e=1
will raise an Attribute error. On the otherhand: Python allows you to do fantastic Metaclass programming:
>>>from new import classobj
>>>Foo2 = classobj('Foo2',(Foo,),{'bar':lambda self:'bar'})
>>>Foo2().bar()
>>>'bar'
>>>Foo2().say_foo()
>>>foo
I am using Eclipse and PyDev with Iron Python on a Windows XP machine. I have a class definition that takes an object as an argument which is itself an instantiation of another class like this:
myObject1 = MyClass1()
myObject2 = MyClass2(myObject1)
The two class definitions are in different modules, myclass1.py and myclass2.py and I was hoping I could get auto completion to work on myObject1 when it is being used in myclass2. In other words, in the file myclass2.py I might have something like this:
""" myclass2.py """
class MyClass2():
def __init__(self, myObject1):
self.myObject1 = myObject1
self.myObject1. <============== would like auto code completion here
Is it possible to make this work?
Thanks!
Using Jython in PyDev/Eclipse, I've wondered about this too. Code completion should work for MyClass1 methods you've used somewhere else in MyClass2, but not for the entire API. I think it's because you can add and remove methods from a class on the fly, so Eclipse can't guarantee that any particular method exists, or that a list of methods is complete.
For example:
>>> class a:
... def b(self):
... print('b')
...
>>> anA = a()
>>> anA.b()
b
>>> del a.b
>>> anA.b()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: a instance has no attribute 'b'
So if code completion showed you the method b() here, it would be incorrect.
Similarly,
>>> class a:
... pass
...
>>> anA = a()
>>> anA.b()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: a instance has no attribute 'b'
>>> def b(self):
... print('b')
...
>>> a.b = b
>>> anA.b()
b
So code completion that didn't show the method b() would be incorrect.
I could be wrong, but I think it's a solid guess. :)
With a spam line (if False ...) with creating object, it's OK with my Pydev 2.5.
""" myclass2.py """
class MyClass2():
def __init__(self, myObject1):
if False : myObject1 = MyClass1()
self.myObject1 = myObject1
self.myObject1. <============== would like auto code completion here
Do you have an __init__.py in your source folder? It can be empty, but it should exist in all folders so that Python knows to read the files contained therein for Classes for the purpose of autocompletion.