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.
Related
I'm going crazy trying to perform simple editing while creating a Python class constructor. I can create the simple class and constructor variable but once I try to change the names of the variable I get a KeyError.
The class is below:
class Collect:
def __init__(self, **kwargs):
self.foo = kwargs["foo"]
And the script where I instantiate the class and print out its attributes is below:
import mapper as m
payload = m.Collect(foo="Hello")
print(payload.foo)
Now this works just fine, but if I change "foo" to "bar" I get a KeyError Like below:
class Collect:
def __init__(self, **kwargs):
self.bar = kwargs["bar"]
and then running:
import mapper as m
payload = m.Collect(bar="Hello")
print(payload.bar)
will throw the following error:
Traceback (most recent call last): File "<stdin>", line 1, in
<module> File
"/path/to/mapper.py",
line 8, in __init__
self.bar = kwargs["bar"] KeyError: 'foo'
And the print function will throw the error below:
Traceback (most recent call last): File "<stdin>", line 1, in
<module> AttributeError: 'Collect' object has no attribute 'bar'
The weird thing is that if I hit save and then close VSCode and reopen, the new class with bar will work just fine. And, also even if I don't close VSCode the class will instantiate and the print statement will run just fine when I switch to Debug mode and run it. But when I try to highlight it and run a selection it throws that error.
How can I just test if the code works using the run selection operations and not relying on running in debug mode with breakpoints or having to close and reopen VSCode?
The solution was to reload my Python session. The VSCode reload extension makes this easy.
In the documentation on instance methods it states that:
Methods also support accessing (but not setting) the arbitrary function attributes on the underlying function object.
But I can't seem to be able to verify that restriction. I tried setting both an arbitrary value and one of the "Special Attributes" of functions:
class cls:
def foo(self):
f = self.foo.__func__
f.a = "some value" # arbitrary value
f.__doc__ = "Documentation"
print(f.a, f.__doc__)
When executed, no errors are produced and the output is as expected:
cls().foo() # prints out f.a, f.__doc__
What is it that I'm misunderstanding with the documentation?
You are misunderstanding what is being said. It says that you can access but not set the attributes of the underlying function object from the method!
>>> class Foo:
... def foo(self):
... self.foo.__func__.a = 1
... print(self.foo.a)
... self.foo.a = 2
...
>>> Foo().foo()
1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in foo
AttributeError: 'method' object has no attribute 'a'
Note how foo.a is updated when you set it on the __func__ value, but you cannot set it directly using self.foo.a = value.
So the function object can be modified as you please, the method wrapper only provides read-only access to the attributes on the underlying function.
A bit of background
I'm writing a python module for my own use, and I'm using Python's logging module. There are handlers and formatters and even a pair of functions I create that (for the most part) won't be used anywhere else. However, I still want to be able to access and modify these variables elsewhere (for instance, other closely-coupled modules or scripts)
A simple namespace
What I'm currently doing is using a class definition to group all of my variables together, like this:
class _Logging:
'''A little namespace for our logging facilities. Don't try to instantiate
it: all it does is group together some logging objects and keep them out of
the global namespace'''
global logger
def __init__(self):
raise TypeError("that's not how this works...")
def gz_log_rotator(source, dest):
'''accept a source filename and a destination filename. copy source to
dest and add gzip compression. for use with
logging.handlers.RotatingFileHandler.rotator.'''
with gzip.open(dest, 'wb', 1) as ofile, open(source, 'rb') as ifile:
ofile.write(ifile.read())
os.remove(source)
def gz_log_namer(name):
'''accept a filename, and return it with ".gz" appended. for use with
logging.handlers.RotatingFileHandler.namer.'''
return name + ".gz"
fmtr = logging.Formatter(
'[%(asctime)s:%(name)s:%(thread)05d:%(levelname)-8s] %(message)s')
gz_rotfile_loghandler = logging.handlers.RotatingFileHandler(
'%s.log' % __name__, mode='a', maxBytes=(1024**2 * 20), backupCount=3)
gz_rotfile_loghandler.setLevel(5)
gz_rotfile_loghandler.setFormatter(fmtr)
gz_rotfile_loghandler.rotator = gz_log_rotator
gz_rotfile_loghandler.namer = gz_log_namer
simplefile_loghandler = logging.FileHandler(
'%s.simple.log' % __name__, mode='w')
simplefile_loghandler.setLevel(15)
simplefile_loghandler.setFormatter(fmtr)
stream_loghandler = logging.StreamHandler()
stream_loghandler.setLevel(25)
stream_loghandler.setFormatter(fmtr)
logger = logging.getLogger(__name__)
logger.setLevel(5)
logger.addHandler(gz_rotfile_loghandler)
logger.addHandler(simplefile_loghandler)
logger.addHandler(stream_loghandler)
However, pylint complains (and i agree) that methods defined in a class should either be static methods, or follow the naming conventions for first parameters (e.g. gz_log_rotator(self, dest)), which is not how the function is used, and would be much more confusing.
Fun Fact
During this process i've also discovered that instances of classmethod and staticmethod are not in and of themselves callable (???). While a method defined in a class namespace is callable both within and without, classmethods and staticmethods are only callable when accessed through their class (at which point they refer to the underlying function, not the classmethod/staticmethod object)
>>> class Thing:
... global one_, two_, three_
... def one(self):
... print('one')
... #classmethod
... def two(cls):
... print('two')
... #staticmethod
... def three():
... print('three')
... one_, two_, three_ = one, two, three
...
>>> Thing.one()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: one() missing 1 required positional argument: 'self'
>>> Thing.two()
two
>>> Thing.three()
three
>>> # all as expected
>>> one_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: one() missing 1 required positional argument: 'self'
>>> # so far so good
>>> two_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'classmethod' object is not callable
>>> # what?
>>> three_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
>>> # ???
My Question
Is there a better way to hold these variables without polluting my namespace?
The code I have works correctly, but it makes me feel a little unclean. I could define a function that would only be called once and then immediately call it, but then I either lose references to everything I don't return, or i'm back to polluting the global namespace. I could just make everything _hidden, but I feel like they should be logically grouped. I could make _Logging a bona fide class, put all of my stuff in an __init__ function and tack all my little variables onto self, but that also feels inelegant. I could create another file for this, but so far I've gotten by with everything held in the same file. The only other option that seemed palatable is to make the two functions staticmethods and only refer to them through our class (i.e. _Logging.gz_log_namer), but it would seem that is also impossible.
>>> class Thing:
... #staticmethod
... def say_hello():
... print('hello!')
... Thing.say_hello()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in Thing
AttributeError: type object 'Thing' has no attribute 'say_hello'
>>>
As it stands, the best option I see is to use the selfless methods.
you can create a new class that inherit from staticmethod class, and add __call__ method to the class.
for example:
class callablestatic(staticmethod):
def __init__(self, func):
super().__init__(func)
self.func = func
def __call__(self, *args, **kwargs):
# the __call__ method allows you to call the class instance
return self.func(*args, **kwargs)
then use it in your class:
class Thing:
#callablestatic
def hello(name):
print(f"hello {name}")
hello("John") # works
but better create new file and import it as a module
Sorry for answering 2 years later, but this could help someone.
You could make your methods static, and create another static method (ex. init), calling it right after initializing the class. Then use setattr to keep the references to your variables.
For setting multiple class variables, you can use
[setattr(Class, name, value) for name,value in locals().items()]
inside the method.
Full code:
class _Logging:
'''A little namespace for our logging facilities. Don't try to instantiate
it: all it does is group together some logging objects and keep them out of
the global namespace'''
def __init__(self):
raise TypeError("that's not how this works...")
#staticmethod
def gz_log_rotator(source, dest):
'''accept a source filename and a destination filename. copy source to
dest and add gzip compression. for use with
logging.handlers.RotatingFileHandler.rotator.'''
with gzip.open(dest, 'wb', 1) as ofile, open(source, 'rb') as ifile:
ofile.write(ifile.read())
os.remove(source)
#staticmethod
def gz_log_namer(name):
'''accept a filename, and return it with ".gz" appended. for use with
logging.handlers.RotatingFileHandler.namer.'''
return name + ".gz"
#staticmethod
def init():
global logger
fmtr = logging.Formatter(
'[%(asctime)s:%(name)s:%(thread)05d:%(levelname)-8s] %(message)s')
gz_rotfile_loghandler = logging.handlers.RotatingFileHandler(
'%s.log' % __name__, mode='a', maxBytes=(1024**2 * 20), backupCount=3)
gz_rotfile_loghandler.setLevel(5)
gz_rotfile_loghandler.setFormatter(fmtr)
gz_rotfile_loghandler.rotator = _Logging.gz_log_rotator
gz_rotfile_loghandler.namer = _Logging.gz_log_namer
simplefile_loghandler = logging.FileHandler(
'%s.simple.log' % __name__, mode='w')
simplefile_loghandler.setLevel(15)
simplefile_loghandler.setFormatter(fmtr)
stream_loghandler = logging.StreamHandler()
stream_loghandler.setLevel(25)
stream_loghandler.setFormatter(fmtr)
logger = logging.getLogger(__name__)
logger.setLevel(5)
logger.addHandler(gz_rotfile_loghandler)
logger.addHandler(simplefile_loghandler)
logger.addHandler(stream_loghandler)
[setattr(_Logging, name, value) for name,value in locals().items()]
_Logging.init()
The following are test classes with methods not taking in cls or self arguments and dont have #staticmethod decorator. They work like normal static methods without complaining about arguments. This seems contrary to my understanding of python methods. Does python automatically treat non-class, non-instance methods as static?
>>> class Test():
... def testme(s):
... print(s)
...
>>> Test.testme('hello')
hello
>>> class Test():
... def testme():
... print('no')
...
>>> Test.testme()
no
P.S: I am using python3.4
It sort of does, yes. However, note that if you call such an "implicit static method" on an instance, you will get an error:
>>> Test().testme()
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
Test().testme()
TypeError: testme() takes 0 positional arguments but 1 was given
This is because the self parameter still gets passed, which doesn't happen with a proper #staticmethod:
>>> class Test:
#staticmethod
def testme():
print('no')
>>> Test.testme()
no
>>> Test().testme()
no
Note that this doesn't work in Python 2:
>>> class Test(object):
... def testme():
... print 'no'
...
>>> Test.testme()
Traceback (most recent call last):
File "<ipython-input-74-09d78063da08>", line 1, in <module>
Test.testme()
TypeError: unbound method testme() must be called with Test instance as first argument (got nothing instead)
But in Python 3, unbound methods were removed, as Alex Martelli points out in this answer. So really all you're doing is calling a plain function that happens to be defined inside the Test class.
Does Python have extension methods like C#? Is it possible to call a method like:
MyRandomMethod()
on existing types like int?
myInt.MyRandomMethod()
You can add whatever methods you like on class objects defined in Python code (AKA monkey patching):
>>> class A(object):
>>> pass
>>> def stuff(self):
>>> print self
>>> A.test = stuff
>>> A().test()
This does not work on builtin types, because their __dict__ is not writable (it's a dictproxy).
So no, there is no "real" extension method mechanism in Python.
It can be done with Forbidden Fruit (https://pypi.python.org/pypi/forbiddenfruit)
Install forbiddenfruit:
pip install forbiddenfruit
Then you can extend built-in types:
>>> from forbiddenfruit import curse
>>> def percent(self, delta):
... return self * (1 + delta / 100)
>>> curse(float, 'percent', percent)
>>> 1.0.percent(5)
1.05
Forbidden Fruit is fundamentally dependent on the C API, it works only on cpython implementations and won’t work on other python implementations, such as Jython, pypy, etc.
not sure if that what you're asking but you can extend existing types and then call whatever you like on the new thing:
class int(int):
def random_method(self):
return 4 # guaranteed to be random
v = int(5) # you'll have to instantiate all you variables like this
v.random_method()
class int(int):
def xkcd(self):
import antigravity
print(42)
>>>v.xkcd()
Traceback (most recent call last):
File "<pyshell#81>", line 1, in <module>
v.xkcd()
AttributeError: 'int' object has no attribute 'xkcd'
c = int(1)
>>> c.random_method()
4
>>> c.xkcd()
42
hope that clarifies your question
The following context manager adds the method like Forbidden Fruit would without the limitations of it. Besides that it has the additional benefit of removing the extension method afterwards:
class extension_method:
def __init__(self, obj, method):
method_name = method.__name__
setattr(obj, method_name, method)
self.obj = obj
self.method_name = method_name
def __enter__(self):
return self.obj
def __exit__(self, type, value, traceback):
# remove this if you want to keep the extension method after context exit
delattr(self.obj, self.method_name)
Usage is as follows:
class C:
pass
def get_class_name(self):
return self.__class__.__name__
with extension_method(C, get_class_name):
assert hasattr(C, 'get_class_name') # the method is added to C
c = C()
print(c.get_class_name()) # prints 'C'
assert not hasattr(C, 'get_class_name') # the method is gone from C
I've had great luck with the method described here:
http://mail.python.org/pipermail/python-dev/2008-January/076194.html
I have no idea if it works on builtins though.
Another option is to override the meta-class. This allows you to, among other things, specify functions that should exist in all classes.
This article starts to discuss it:
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html