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
Related
I would like to store a bunch of variables under a Python namespace without creating a separate module. I notice that the result of ArgumentParser's parse_args() is a argparse.Namespace object. You can access the arguments through dot-syntax.
from argparse import ArgumentParser
parser = ArgumentParser()
# some arg definitions here...
args = parser.parse_args() # returns a `argparse.Namespace` object
How can I create the equivalent of an argparse.Namespace? I know I can do something similar with a dict but I would like to use dot-syntax. Is there any built-in class that just lets you assign arbitrary attributes?
Starting with python3.3 you can use types.SimpleNamespace.
However an alternative is simply:
class Namespace(object):
pass
namespaceA = Namespace()
namespaceA.x = 1
The full code for SimpleNamespace isn't much longer.
Note that you cannot simply use an object instance:
>>> o = object()
>>> o.x = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'x'
This is because instances of object do not have a __dict__ attribute:
>>> vars(object())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute
Which means you cannot set the attributes of an instance of object.
Any object subclass that does not have the __slots__ attribute set does have the __dict__ which is used (by default) to store/retrieve attributes:
>>> class Namespace(object):
... pass
...
>>> a = Namespace()
>>> a.x = 1 # same as as.__dict__['a'] = 1
>>> a.__dict__
{'x': 1}
For further information about attribute setting/lookup you should learn about descriptors.
A class can be used as a namespace, where the variables are class members:
class Namespace1:
foo = 'a'
bar = 5
To prevent callers from trying to instantiate, you can use a baseclass like:
class objectless(object):
def __new__(cls, *args, **kwargs):
raise RuntimeError('%s should not be instantiated' % cls)
And use it like:
class Namespace1(objectless):
...
It sounds like you want a python class. See the docs.
Depending on what you want exactly, you can define a bunch of variables as attributes of a class (either a variable of an instance or of the class itself) and access them that way.
If you want "the equivalent of an argparse.Namespace", use argparse.Namespace:
from argparse import Namespace
ns = Namespace(a=1)
print ns.a
If I'm understanding correctly, you want to dynamically add attributes to it. For example, a class parses command-line flags you access them directly like args.verbose, right? If so, you may be thinking of setattr() that lets you add arbitrary attributes.
class Foo(object):
pass
foo = Foo()
setattr(foo, 'ack', 'bar')
print(foo.ack) # prints 'bar'
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 am a newbie to Python. I got some Python sample code from a software vendor who extended their software API with boost.python so we can call them in Python. I am confused with some of the segments, such as:
settings = zoo.AddAnimalSettings(carni_bird_list)
settings.Name = 'birds'
settings.Type = settings.Type.enum.Bird
settings.water_min = 1, units.Litre
settings.food_min = 10, units.Gram
All the variable names are replaced to be these funny things anyway, just for explanation of the general idea.
So here the problem is in the 3rd line. How can we set the variable settings.Type with its sub property settings.Type.enum.Bird, where enum.Bird I suppose is some kind of enum of different kind of animals, which is a sub-property of settings.Type?
I tried doing some test to add one line following the above 5 lines to see if enum.Bird is still there:
settings.Type = settings.Type.enum.Bird
and it works ok.
So for this instance settings, it's sub property Type is not overwritten by its sub property of enum.Bird, it still knows enum.Bird is its sub-property.
Can you advise if I need to implement this line in Python, how can I do that?
I suppose it would be a quite interesting knowledge for people learning Python, so I raised this question here for discussing. I am trying to think in a C++ way, but I didn't figure it out.
I don't really see what's the issue. Consider an Enum defined in python:
import enum
class Type(enum.Enum):
Bird = 0
Cat = 1
The Type.Bird and Type.Cat are instances of the Type class:
>>> Type.Bird
<Type.Bird: 0>
>>> Type.Cat
<Type.Cat: 1>
As such they have access to their own class, which is Type:
>>> Type.Bird.__class__
<enum 'Type'>
Now you can just add a property to the Type class and obtain that behaviour:
class Type(enum.Enum):
Bird = 0
Cat = 1
#property
def enum(self):
return self.__class__
and now you have:
>>> Type.Bird
<Type.Bird: 0>
>>> Type.Bird.enum
<enum 'Type'>
>>> Type.Bird.enum.Bird
<Type.Bird: 0>
>>> Type.Bird.enum.Cat
<Type.Cat: 1>
Note that while the above allows you to write Bird.enum doesn't allow you to access as in Type.enum because this would return the property object.
To obtain the exact behaviour you see in that code you could:
Set the settings.Type attribute to be an instance of Type (possibly an Invalid one) and be done:
def AddAnimalSettings(*args)
settings = MyClass(*args)
settings.Type = Type.Bird
return settings
Replace the use of property with a custom made descriptor that will handle the access via the class too. In this case read the documentation about property which also provides its python code equivalent. The case you have to change is __get__ when obj is None:
class MyProperty(object):
# omissis
def __get__(self, obj, objtype=None):
if obj is None:
return objtype # <-- changed this line
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
Use this as:
class Type(enum.Enum):
Bird = 0
Cat = 1
#MyProperty
def enum(self):
return self.__class__
And now you have:
>>> Type.enum
<enum 'Type'>
so that Type.enum.Bird works.
This is more of a curiosity question than anything else. I'm new with Python and playing around with it. I've just looked at the base64 module. What if instead of doing:
import base64
string = 'Foo Bar'
encoded = base664.b64encode
I wanted to do something like:
>>> class b64string():
>>> <something>
>>>
>>> string = b64string('Foo Bar')
>>> string
'Foo Bar'
>>> string.encode64()
'Rm9vIEJhcg=='
>>> string
'Rm9vIEJhcg=='
>>> string.assign('QmFyIEZvbw==')
>>> string
'QmFyIEZvbw=='
>>> string.b64decode()
'Bar Foo'
>>> string
'Bar Foo'
Is there a simple, pythonic way to create that class?
I've begun with this:
>>> class b64string(base64):
... def __init__(self, v):
... self.value=v
And already I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
And don't get me started on (just to see what would happen):
>>> class b64string(str, base64): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I know how to do it manually by listing all of the attributes of base64 in a new class and calling them with the stored value as argument. But is there a neat, pythonic way to do this? Is it a bad idea to do it? The idea would be, if needed, to do it with many such modules and have "super strings" that would have as modules all the things I would need to do with them. Is that bad? Is it un-pythonic? If it is pythonic, how is it done?
I don't think creating such complex string-like classes is a good idea, but if you really want to, here's a simple snippet that runs your examples.
First, we define a class that's a generic string-wrapper. Its core is a __getattr__ function that forwards every method call to a given self.module, adding self.string as the first parameter and remembering the result on self.string.
import base64
class ModuledString(object):
def __init__(self, string):
self.string = string
def __getattr__(self, attrname):
def func(*args, **kwargs):
result = getattr(self.module, attrname)(self.string, *args, **kwargs)
self.string = result
return result
return func
def __str__(self):
return str(self.string)
Creating a string-wrapper with base64 capabilities is then easy:
class B64String(ModuledString):
module = base64
if __name__ == '__main__':
string = B64String('Foo Bar')
print string
# 'Foo Bar'
print string.b64encode()
# 'Rm9vIEJhcg=='
print string
# 'Rm9vIEJhcg=='
string.string = 'QmFyIEZvbw=='
print string
# 'QmFyIEZvbw=='
print string.b64decode()
# 'Bar Foo'
Note that the above examples work only because b64encode and b64decode take a string as the first argument and return a string as the result (there is no validation in my __getattr__ function). A random function from some random module would probably raise some kind of exception. So, after all, it would be better to restrict the usage to a predefined set of functions from a given module, but it should be easy now.
I repeat, I don't recommend using such code in any serious project, only for fun.
I've seen decorators that let you mark a function a deprecated so that a warning is given whenever that function is used. I'd like to do the same thing but for a global variable, but I can't think of a way to detect global variable accesses. I know about the globals() function, and I could check its contents, but that would just tell me if the global is defined (which it still will be if the function is deprecated and not all out removed) not if it's actually being used. The best alternative I can think of is something like this:
# myglobal = 3
myglobal = DEPRECATED(3)
But besides the problem of how to get DEPRECATED to act exactly like a '3', I'm not sure what DEPRECATED could do that would let you detect every time it's accessed. I think the best it could do is iterate through all of the global's methods (since everything in Python is an object, so even '3' has methods, for converting to string and the like) and 'decorate' them to all be deprecated. But that's not ideal.
Any ideas? Has anyone else tackled this problem?
You can't do this directly, since theres no way of intercepting the module access. However, you can replace that module with an object of your choosing that acts as a proxy, looking for accesses to certain properties:
import sys, warnings
def WrapMod(mod, deprecated):
"""Return a wrapped object that warns about deprecated accesses"""
deprecated = set(deprecated)
class Wrapper(object):
def __getattr__(self, attr):
if attr in deprecated:
warnings.warn("Property %s is deprecated" % attr)
return getattr(mod, attr)
def __setattr__(self, attr, value):
if attr in deprecated:
warnings.warn("Property %s is deprecated" % attr)
return setattr(mod, attr, value)
return Wrapper()
oldVal = 6*9
newVal = 42
sys.modules[__name__] = WrapMod(sys.modules[__name__],
deprecated = ['oldVal'])
Now, you can use it as:
>>> import mod1
>>> mod1.newVal
42
>>> mod1.oldVal
mod1.py:11: UserWarning: Property oldVal is deprecated
warnings.warn("Property %s is deprecated" % attr)
54
The downside is that you are now performing two lookups when you access the module, so there is a slight performance hit.
You could make your module into a class (see e.g this SO question) and make that deprecated global into a property, so you can execute some of your code when it's accessed and provide the warning you desire. However, this does seem a bit of an overkill.
Behold:
Code
from types import *
def wrapper(f, warning):
def new(*args, **kwargs):
if not args[0].warned:
print "Deprecated Warning: %s" % warning
args[0].warned = True
return f(*args, **kwargs)
return new
class Deprecated(object):
def __new__(self, o, warning):
print "Creating Deprecated Object"
class temp(o.__class__): pass
temp.__name__ = "Deprecated_%s" % o.__class__.__name__
output = temp.__new__(temp, o)
output.warned = True
wrappable_types = (type(int.__add__), type(zip), FunctionType)
unwrappable_names = ("__str__", "__unicode__", "__repr__", "__getattribute__", "__setattr__")
for method_name in dir(temp):
if not type(getattr(temp, method_name)) in wrappable_types: continue
if method_name in unwrappable_names: continue
setattr(temp, method_name, wrapper(getattr(temp, method_name), warning))
output.warned = False
return output
Output
>>> a=Deprecated(1, "Don't use 1")
Creating Deprecated Object
>>> a+9
Deprecated Warning: Don't use 1
10
>>> a*4
4
>>> 2*a
2
This can obviously be refined, but the gist is there.
This is one of the main rationale for PEP 562 (implemented in Python 3.7):
Typical workarounds are assigning __class__ of a module object to a
custom subclass of types.ModuleType or replacing the sys.modules item
with a custom wrapper instance. It would be convenient to simplify
this procedure by recognizing __getattr__ defined directly in a module
that would act like a normal __getattr__ method, except that it will
be defined on module instances. For example:
# lib.py
from warnings import warn
deprecated_names = ["old_function", ...]
def _deprecated_old_function(arg, other):
...
def __getattr__(name):
if name in deprecated_names:
warn(f"{name} is deprecated", DeprecationWarning)
return globals()[f"_deprecated_{name}"]
raise AttributeError(f"module {__name__} has no attribute {name}")
# main.py
from lib import old_function # Works, but emits the warning